1 Introduction

1.1 What am I hoping to achieve with this project?

  • predict how long it will take to learn a piece based on various features
  • discover insights into my practice habits and find areas where I need to improve
  • develop a recommender tool of piano pieces for others to select from based on factors of interest
  • hopefully act as a source of inspiration/realistic piano progress for others who want to learn a musical instrument

Context: I started playing the piano in 2018 as a complete beginner and I’ve been tracking my practice time for around 2 and a half years. I now decided to put that to good use and see what interesting patterns I might be able to find.

1.2 Data collection

  • imputed conservative estimations for the first 10 months of the first year (Jan ’18 to Oct ’18)
  • everything from Dec ’18 onwards was tracked using Toggl, a time-tracking app/tool
  • these times include my practice sessions (usually in short bouts of 30 minutes); piano lessons are excluded (usually 2-3 hours total per month)
  • the Extract, Transform, Load script is available in the global.R file of this repo

Disclaimer: I am not affiliated with Toggl. I started using it a few years ago because it provided all the functionality I needed and loved its minimalistic design. The standard membership, which I use, is free of charge.

2 Key insights

2.1 Summary:

  • identified various trends in average daily practice session, time of year, etc
  • pieces could take me anywhere from around 4 hours to 40+ hours, subject to difficulty (as assessed by the ABRSM grade)
  • the Random Forrest model was shown to be the most optimal model
    • Rsquared (0.585)
    • MAE - 5.9 hours
    • RMSE - 7.5 hours
    • Looking at the variability of errors, there is still a tendency to over-predict for pieces that took very little and under-predict for the more difficult ones. There could be two main reasons for this:
      • practicing an old piece in order to further improve (which naturally adds more practice time as I re-learn it)
      • learning easier pieces later on in my journey which means I will learn them faster than expected (based on my earlier data where a piece of a similar difficulty took longer)
  • the most important variables were shown to be the number of length of the piece, standard of playing (performance vs casual) and experience(cumulative hours before first practice session on each piece)
knitr::opts_chunk$set(
    echo = FALSE, # show all of the code
    tidy = FALSE, # cleaner code printing
    size = "small", # smaller code
    
    fig.path = "figs/",# where the figures will end up
    out.width = "100%",

    message = FALSE,
    warning = FALSE
    )

3 Exploratory Data Analysis (EDA)

3.1 Piano practice timeline

3.2 How long did I practice per piece?

Based on the level at the time and the difficulty of the piece, we can see that each piece took around 10-30 hours of practice.

3.3 How consistent was my practice?

Generally, I’ve done pretty well to maintain a high level of consistency with the exception of August/December. This is usually where I tend to take annual leave.

3.4 Was there a trend in my amount of daily average practice?

We can see that my practice time was correlated with the consistency, where the average session was much shorter in the months I was away from the piano. There’s also a trend where my practice close to an exam session was significantly higher than any other time of the year. Can you spot in which month I had my exam in 2019? What about the end of 2020?

average practice length per month includes the days in which I did not practice

overall

Year on Year

Similar trends as before are apparent where my average daily session is longer before the exams than any other time in the year and a dip in the months where I usually take most of my annual leave. I really do need to start picking up the pace and get back to where I used to be.

3.5 Did COVID significantly impact my practice time?

graph

Despite a similar median, we can see that the practice sessions were less likely to be over 80 min after COVID. We can test if this was a significant impact with a t-test.

skewness assumption

Given the extremely low p-value, the Shapiro-Wilk normality test implies that the distribution of the data is significantly different from a normal distribution and that we cannot assume the normality. However, we’re working with the entire population dataset for each class and thus, unlike the independence of data, this assumption is not crucial.

Shapiro-Wilk normality test
group statistic p.value method
After COVID 0.9607325 3e-07 Shapiro-Wilk normality test
Before COVID 0.9549818 0e+00 Shapiro-Wilk normality test

equal variances assumption

We can see that with a large p value, we should fail to reject the Null hypothesis (Ho) and conclude that we do not have evidence to believe that population variances are not equal and use the equal variances assumption for our t test

Levene’s test
statistic p.value df df.residual
0.0410026 0.8395891 1 732

t-test

My practice sessions post-COVID are significantly shorter than those before the pandemic. This might be surprising, given that we were in the lockdown most of the time. However, I’ve been spending my time doing a few other things such as improving my technical skillset with R (this analysis wouldn’t have been possible otherwise) and learning italian.

.y. group1 group2 n1 n2 statistic df p p.signif
Duration Before COVID After COVID 433 301 3.319481 732 0.000947 ***

3.6 What type of music do I tend to play?

by genre

by composer

by piece

3.7 Relation between difficulty and number of practice hours

ABRSM grade

Simplified, ABBRSM grades are a group of 8 exams based on their difficulty (1 - beginner to 8 - advanced). There are also diploma grades but those are extremely advanced, equivalent to university level studies and out of the scope of this analysis.

More information can be found on their official website at https://gb.abrsm.org/en/exam-support/your-guide-to-abrsm-exams/

level

A further aggregation of ABRSM grades; this is helpful given the very limited dataset within each grade and much easier on the eye. This is an oversimplification but they’re classified as: * 1-5: Beginner (1) * 5-6: Intermediate (2) * 7-8: Advanced (3)

3.8 What about the piece length?

3.9 Learning effect - do pieces of the same difficulty become easier to learn with time?

We can spot a trend where the time required to learn a piece of a similar difficulty (ABRSM Grade) decreases as my ability to play the piano increases (as judged by cumulative hours of practice). We should keep this in mind and include it as a variable into our prediction model.

3.10 Does “pausing” a piece impact the total time required to learn it?

How do we differentiate between pieces that we learn once and those that we come back to repeatedly? Examples could include wanting to improve the playing further, loving it so much we wanted to relearn it, preparing it for a new performance, etc.

As anyone that ever played the piano knows, re-learning a piece, particularly after you “drop” it for a few months/years, results in a much better performance/understanding of the piece. I definitely found that to be true in my experience, particularly with my exam pieces.The downside is that these pieces take longer to learn.

3.11 Repertoire

Repertoire
Project Duration Genre ABRSM Level Standard Length Experience Break Started
Elton John - Rocket man 47 Modern 7 Advanced Performance 4.0 1130 No 2020-12-08
Schumann - Träumerei 14 Romantic 7 Advanced Average 3.0 1087 No 2020-11-09
Mozart - Allegro (3rd movement) K282 28 Classical 6 Intermediate Average 3.3 1081 Yes 2020-11-05
Ibert - Sérénade sur l’eau 10 Modern 6 Intermediate Performance 1.7 1038 No 2020-09-24
Kuhlau - Rondo Vivace 24 Classical 6 Intermediate Average 2.2 1014 No 2020-08-03
C. Hartmann - The little ballerina 21 Romantic 6 Intermediate Performance 2.0 998 No 2020-07-14
Schumann - Lalling Melody 5 Romantic 1 Beginner Average 1.3 981 No 2020-06-28
Schumann - Melody 4 Romantic 1 Beginner Average 1.0 972 No 2020-06-20
Clementi - Sonatina no 3 - Mov 2 3 Classical 1 Beginner Performance 1.0 952 No 2020-06-04
Clementi - Sonatina no 3 - Mov 3 20 Classical 4 Beginner Performance 2.0 952 No 2020-06-04
Chopin - Waltz in Fm 27 Romantic 6 Intermediate Performance 2.0 895 Yes 2020-04-18
Clementi - Sonatina no 3 - Mov 1 30 Classical 4 Beginner Performance 2.7 877 No 2020-04-07
Schumann - Kinderszenen 1 10 Romantic 5 Intermediate Average 2.0 855 No 2020-03-25
Bach - Prelude in G from Cello Suite No 1 25 Baroque 5 Intermediate Average 2.5 788 No 2020-02-04
Georg Böhm - Minuet in G 7 Baroque 1 Beginner Average 1.0 780 Yes 2020-01-27
Bach - Invention 4 in Dm 21 Baroque 5 Intermediate Performance 1.7 777 No 2020-01-25
Chopin - Contredanse in Gb 23 Romantic 6 Intermediate Performance 2.2 762 No 2020-01-16
Bach - Minuet in Gm - 115 7 Baroque 1 Beginner Average 1.3 750 No 2020-01-07
Bach - Minuet in G - 114 4 Baroque 1 Beginner Average 2.0 726 No 2019-12-06
Elton John - Your song (Arr Cornick) 36 Modern 5 Intermediate Performance 3.3 713 No 2019-11-21
Poulenc - Valse Tyrolienne 17 Modern 5 Intermediate Performance 1.7 562 No 2019-09-02
Bach - Prelude in Cm - 934 25 Baroque 5 Intermediate Performance 2.4 536 No 2019-08-15
Schumann - Volksliedchen 10 Romantic 2 Beginner Average 1.8 501 No 2019-07-01
Haydn - Andante in A 39 Classical 5 Intermediate Average 2.8 468 Yes 2019-06-08
Schumann - Remembrance 34 Romantic 5 Intermediate Performance 2.2 422 Yes 2019-04-28
Bach - Minuet in G - 116 8 Baroque 1 Beginner Average 2.0 361 Yes 2019-03-04
Bach - Invention 1 in C 27 Baroque 5 Intermediate Performance 1.7 350 Yes 2019-02-22
Chopin - Waltz in Am 26 Romantic 4 Beginner Performance 2.5 305 Yes 2019-01-07

4 Modelling

Question: How long would it take to learn a piece based on various factors?

4.1 detect outliers

Given the very limited data at the advanced level (Grade 7 ABRSM), those two pieces will be removed. One is an extreme outlier as well which will significantly impact our models.

4.2 missing values

There are no missing values in the modelling dataset following the ETL process.

4.3 Feature engineering

  • categorical:
    • ABRSM grade: 1 to 8
    • Genre: Baroque, Classical, Romantic, Modern
    • Break: learning it continuously or setting it aside for a while (1 month minimum)
    • Standard of practice: public performance or average (relative to someone’s level of playing)
  • numerical:
    • Experience: total hours practiced before the first practice session on each piece
    • piece Length: minutes

4.4 Pre-processing

Let’s use some basic standardisation offered by the caret package such as centering (subtract mean from values) and scaling (divide values by standard deviation).

4.5 Resampling

Given the small size of the dataset, bootstrapping resampling method will be applied.

4.6 Model selection

# set number of clusters 
clusters <- 4

# run them all in parallel
cl <- makeCluster(clusters, type = "SOCK")
 
# register cluster train in paralel
registerDoSNOW(cl)

# train models
model <- train(Duration ~ ABRSM + Genre + Length + Cumulative_Duration + Break + Standard,
                  data = model_data,
                  method = "ranger",
                  tuneLength = 100,
                  trControl = train.control)


model2 <- train(Duration ~ ABRSM + Genre + Length + Cumulative_Duration + Break + Standard,
                data = model_data,
                method = "lmStepAIC",
                tuneLength = 100,
                trControl = train.control)


model3 <- train(Duration ~ ABRSM + Genre + Length + Cumulative_Duration + Break + Standard,
                data = model_data,
                method = "lm",
                tuneLength = 100,
                trControl = train.control)

model4 <- train(Duration ~ ABRSM + Genre + Length + Cumulative_Duration + Break + Standard,
                data = model_data,
                method = "ridge",
                tuneLength = 100,
                trControl = train.control)

model5 <- train(Duration ~ ABRSM + Genre + Length + Cumulative_Duration + Break + Standard,
                data = model_data,
                method = "rf",
                tuneLength = 100,
                trControl = train.control)

model6 <- train(Duration ~ ABRSM + Genre + Length + Cumulative_Duration + Break + Standard,
                data = model_data,
                method = "gbm",
                tuneLength = 100,
                trControl = train.control)

model7 <- train(Duration ~ ABRSM + Genre + Length + Cumulative_Duration + Break + Standard,
                data = model_data,
                method = "pls",
                tuneLength = 100,
                trControl = train.control)
 
# shut the instances of R down
stopCluster(cl)

# compare models
model_list <- list(ranger = model, lmStepAIC = model2, lm = model3, ridge = model4, rf = model5, gbm = model6, pls = model7)

model_comparison <- resamples(model_list)

# learning curves to indicate overfitting and underfitting
# hyper parameters 
# https://topepo.github.io/caret/model-training-and-tuning.html#model-training-and-parameter-tuning
# https://topepo.github.io/caret/random-hyperparameter-search.html

We chose the Random Forest model as it was the best performing model. It is known as a model which is:

  • not very sensitive to outliers
  • good for non-linearity
  • variable importance can be biased if categorical variables have few levels (toward high levels) or are correlated
## 
## Call:
## summary.resamples(object = model_comparison)
## 
## Models: ranger, lmStepAIC, lm, ridge, rf, gbm, pls 
## Number of resamples: 25 
## 
## MAE 
##               Min.  1st Qu.   Median     Mean  3rd Qu.      Max. NA's
## ranger    3.216848 4.546412 5.226721 5.350732 6.185954  8.074644    0
## lmStepAIC 4.059373 6.035128 6.625829 7.373961 8.656703 12.293508    0
## lm        3.457466 6.104998 6.831580 7.407868 8.107952 16.638647    0
## ridge     3.514506 5.195608 5.904643 5.936369 7.002558  7.751690   10
## rf        2.867137 5.123509 5.592698 5.959335 6.989707  8.722035    0
## gbm       4.593238 6.146348 6.951988 7.261349 8.076775 16.990824    0
## pls       4.460543 5.041959 5.930350 5.848360 6.295627  7.970644    0
## 
## RMSE 
##               Min.  1st Qu.   Median     Mean   3rd Qu.      Max. NA's
## ranger    4.531594 5.821475 6.907062 6.876131  7.614550 10.521156    0
## lmStepAIC 4.678084 7.290730 8.706652 9.067898 10.179064 15.976038    0
## lm        3.979872 8.065115 8.705383 9.404728 10.412562 19.451739    0
## ridge     4.989087 6.206758 6.862180 7.045983  7.854493  8.687658   10
## rf        3.394308 6.640020 7.115649 7.546307  8.461888 11.065527    0
## gbm       5.906910 7.466537 8.041088 8.843606  8.994092 21.377506    0
## pls       5.322380 6.303446 7.096138 7.043631  7.345444  9.624458    0
## 
## Rsquared 
##                   Min.   1st Qu.    Median      Mean   3rd Qu.      Max. NA's
## ranger    0.2598148174 0.5915672 0.6861549 0.6395133 0.7899287 0.8801139    0
## lmStepAIC 0.0005882529 0.4001020 0.5735153 0.5051570 0.6597403 0.8997367    0
## lm        0.0019980780 0.2879700 0.5871362 0.4965277 0.6363397 0.8958706    0
## ridge     0.3743315404 0.6559275 0.6807293 0.6828744 0.7764227 0.8621330   10
## rf        0.1341300382 0.5248279 0.6068158 0.5858350 0.7012294 0.8842650    0
## gbm       0.0669333944 0.3848695 0.5685371 0.5338006 0.6661362 0.8728232    0
## pls       0.3579501758 0.6342263 0.6727956 0.6723318 0.7638235 0.8898141    0

Based on our regression model, it does not look like we have significant multicollinearity between the full model variables so we can continue as it is.

Variance Inflation Factor (VIF)
names VIF
ABRSM6 4.0
Cumulative_Duration 3.9
ABRSM5 3.5
ABRSM4 3.4
GenreClassical 2.5
Length 2.4
StandardPerformance 2.4
BreakNo 2.1
GenreRomantic 1.9
ABRSM2 1.7
GenreModern 1.7

4.6.1 Actuals vs Predictions

4.6.2 Residual distribution

We can see that the residuals are mostly situated around 0.

4.6.3 Actuals versus Residuals

Looking at the variability of errors, there is still a tendency to over-predict for pieces that took very little and under-predict for the more difficult ones. There could be two main reasons for this:

  • practicing an old piece in order to further improve (which naturally adds more practice time as I re-learn it)
  • learning easier pieces later on in my journey which means I will learn them faster than expected (based on my earlier data where a piece of a similar difficulty took longer)

4.7 Linear Regression (LR) or Random Forest (RF)?

We can see that the Random Forest performed significantly better than the Linear Regression model. This isn’t surprising since there might be non-linear trends within the data, and RFs are known to be more accurate.

Model 1 vs model 2
estimate statistic p.value parameter conf.low conf.high method alternative
1.858421 3.01994 0.0059183 24 0.5883319 3.12851 One Sample t-test two.sided

4.8 How many predictors did the most optimal model have?

4.9 What were the most important variables?

We can now see that the most important variables seemed to be the length of the piece, my experience prior to starting a piece and time difficulty of the piece. These were also confirmed by the linear regression model.

5 Limitations

6 Hardest things about this analysis:

7 Interactive application:

8 What’s next?

LS0tCiAgICBvdXRwdXQ6CiAgICAgIGh0bWxfZG9jdW1lbnQ6CiAKICAgICAgICB0b2M6IHRydWUKICAgICAgICB0b2NfZmxvYXQ6IGZhbHNlCiAgICAgICAgdG9jX2RlcHRoOiAyCiAgICAgICAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlCiAgICAgICAgCiAgICAgICAgY29kZV9mb2xkaW5nOiBoaWRlCiAgICAgICAgY29kZV9kb3dubG9hZDogdHJ1ZQogICAgICAgIAogICAgICAgIGZpZ193aWR0aDogMTUgCiAgICAgICAgZmlnX2hlaWdodDogNgogICAgICAgIGZpZ19hbGlnbjogImNlbnRlciIKICAgICAgICAKICAgICAgICBoaWdobGlnaHQ6IHB5Z21lbnRzCiAgICAgICAgdGhlbWU6IGNlcnVsZWFuCiAgICAgICAgCiAgICAgICAga2VlcF9tZDogdHJ1ZQogICAgICAgIAogICAgdGl0bGU6ICJIdW1hbiBMZWFybmluZyBtZWV0cyBNYWNoaW5lIExlYXJuaW5nIgogICAgc3VidGl0bGU6ICIxLDIwMCsgaG91cnMgb2YgcGlhbm8gcHJhY3RpY2UiCiAgICBhdXRob3I6ICJieSBQZXRlciBIb250YXJ1IgotLS0KCiMgSW50cm9kdWN0aW9uCgojIyBXaGF0IGFtIEkgaG9waW5nIHRvIGFjaGlldmUgd2l0aCB0aGlzIHByb2plY3Q/CgoqIHByZWRpY3QgaG93IGxvbmcgaXQgd2lsbCB0YWtlIHRvIGxlYXJuIGEgcGllY2UgYmFzZWQgb24gdmFyaW91cyBmZWF0dXJlcwoqIGRpc2NvdmVyIGluc2lnaHRzIGludG8gbXkgcHJhY3RpY2UgaGFiaXRzIGFuZCBmaW5kIGFyZWFzIHdoZXJlIEkgbmVlZCB0byBpbXByb3ZlCiogZGV2ZWxvcCBhIHJlY29tbWVuZGVyIHRvb2wgb2YgcGlhbm8gcGllY2VzIGZvciBvdGhlcnMgdG8gc2VsZWN0IGZyb20gYmFzZWQgb24gZmFjdG9ycyBvZiBpbnRlcmVzdAoqIGhvcGVmdWxseSBhY3QgYXMgYSBzb3VyY2Ugb2YgaW5zcGlyYXRpb24vcmVhbGlzdGljIHBpYW5vIHByb2dyZXNzIGZvciBvdGhlcnMgd2hvIHdhbnQgdG8gbGVhcm4gYSBtdXNpY2FsIGluc3RydW1lbnQKCioqQ29udGV4dCoqOiBJIHN0YXJ0ZWQgcGxheWluZyB0aGUgcGlhbm8gaW4gMjAxOCBhcyBhIGNvbXBsZXRlIGJlZ2lubmVyIGFuZCBJJ3ZlIGJlZW4gdHJhY2tpbmcgbXkgcHJhY3RpY2UgdGltZSBmb3IgYXJvdW5kIDIgYW5kIGEgaGFsZiB5ZWFycy4gSSBub3cgZGVjaWRlZCB0byBwdXQgdGhhdCB0byBnb29kIHVzZSBhbmQgc2VlIHdoYXQgaW50ZXJlc3RpbmcgcGF0dGVybnMgSSBtaWdodCBiZSBhYmxlIHRvIGZpbmQuCgojIyBEYXRhIGNvbGxlY3Rpb24KCiogaW1wdXRlZCBjb25zZXJ2YXRpdmUgZXN0aW1hdGlvbnMgZm9yIHRoZSBmaXJzdCAxMCBtb250aHMgb2YgdGhlIGZpcnN0IHllYXIgKEphbiAnMTggdG8gT2N0ICcxOCkKKiBldmVyeXRoaW5nIGZyb20gRGVjICcxOCBvbndhcmRzIHdhcyB0cmFja2VkIHVzaW5nIFRvZ2dsLCBhIHRpbWUtdHJhY2tpbmcgYXBwL3Rvb2wKKiB0aGVzZSB0aW1lcyBpbmNsdWRlIG15IHByYWN0aWNlIHNlc3Npb25zICh1c3VhbGx5IGluIHNob3J0IGJvdXRzIG9mIDMwIG1pbnV0ZXMpOyBwaWFubyBsZXNzb25zIGFyZSBleGNsdWRlZCAodXN1YWxseSAyLTMgaG91cnMgdG90YWwgcGVyIG1vbnRoKQoqIHRoZSAqKkV4dHJhY3QsIFRyYW5zZm9ybSwgTG9hZCoqIHNjcmlwdCBpcyBhdmFpbGFibGUgaW4gdGhlIGdsb2JhbC5SIGZpbGUgb2YgdGhpcyByZXBvCgoqKkRpc2NsYWltZXIqKjogSSBhbSBub3QgYWZmaWxpYXRlZCB3aXRoIFRvZ2dsLiBJIHN0YXJ0ZWQgdXNpbmcgaXQgYSBmZXcgeWVhcnMgYWdvIGJlY2F1c2UgaXQgcHJvdmlkZWQgYWxsIHRoZSBmdW5jdGlvbmFsaXR5IEkgbmVlZGVkIGFuZCBsb3ZlZCBpdHMgbWluaW1hbGlzdGljIGRlc2lnbi4gVGhlIHN0YW5kYXJkIG1lbWJlcnNoaXAsIHdoaWNoIEkgdXNlLCBpcyBmcmVlIG9mIGNoYXJnZS4KCiMgS2V5IGluc2lnaHRzCgojIyBTdW1tYXJ5OgoKKiBpZGVudGlmaWVkIHZhcmlvdXMgdHJlbmRzIGluIGF2ZXJhZ2UgZGFpbHkgcHJhY3RpY2Ugc2Vzc2lvbiwgdGltZSBvZiB5ZWFyLCBldGMKKiBwaWVjZXMgY291bGQgdGFrZSBtZSBhbnl3aGVyZSBmcm9tIGFyb3VuZCA0IGhvdXJzIHRvIDQwKyBob3Vycywgc3ViamVjdCB0byBkaWZmaWN1bHR5IChhcyBhc3Nlc3NlZCBieSB0aGUgQUJSU00gZ3JhZGUpCiogdGhlIFJhbmRvbSBGb3JyZXN0IG1vZGVsIHdhcyBzaG93biB0byBiZSB0aGUgbW9zdCBvcHRpbWFsIG1vZGVsCiAgLSAqKlJzcXVhcmVkKiogKDAuNTg1KQogIC0gKipNQUUqKiAtIDUuOSBob3VycyAKICAtICoqUk1TRSoqIC0gNy41IGhvdXJzCiAgKiBMb29raW5nIGF0IHRoZSB2YXJpYWJpbGl0eSBvZiBlcnJvcnMsIHRoZXJlIGlzIHN0aWxsIGEgdGVuZGVuY3kgdG8gb3Zlci1wcmVkaWN0IGZvciBwaWVjZXMgdGhhdCB0b29rIHZlcnkgbGl0dGxlIGFuZCB1bmRlci1wcmVkaWN0IGZvciB0aGUgbW9yZSBkaWZmaWN1bHQgb25lcy4gVGhlcmUgY291bGQgYmUgdHdvIG1haW4gcmVhc29ucyBmb3IgdGhpczoKICAgICogcHJhY3RpY2luZyBhbiBvbGQgcGllY2UgaW4gb3JkZXIgdG8gZnVydGhlciBpbXByb3ZlICh3aGljaCBuYXR1cmFsbHkgYWRkcyBtb3JlIHByYWN0aWNlIHRpbWUgYXMgSSByZS1sZWFybiBpdCkKICAgICogbGVhcm5pbmcgZWFzaWVyIHBpZWNlcyBsYXRlciBvbiBpbiBteSBqb3VybmV5IHdoaWNoIG1lYW5zIEkgd2lsbCBsZWFybiB0aGVtIGZhc3RlciB0aGFuIGV4cGVjdGVkIChiYXNlZCBvbiBteSBlYXJsaWVyIGRhdGEgd2hlcmUgYSBwaWVjZSBvZiBhIHNpbWlsYXIgZGlmZmljdWx0eSB0b29rIGxvbmdlcikKKiB0aGUgbW9zdCBpbXBvcnRhbnQgdmFyaWFibGVzIHdlcmUgc2hvd24gdG8gYmUgdGhlIG51bWJlciBvZiAqKmxlbmd0aCBvZiB0aGUgcGllY2UqKiwgKipzdGFuZGFyZCBvZiBwbGF5aW5nKiogKHBlcmZvcm1hbmNlIHZzIGNhc3VhbCkgYW5kICoqZXhwZXJpZW5jZSoqKGN1bXVsYXRpdmUgaG91cnMgYmVmb3JlIGZpcnN0IHByYWN0aWNlIHNlc3Npb24gb24gZWFjaCBwaWVjZSkKCmBgYHtyfQprbml0cjo6b3B0c19jaHVuayRzZXQoCiAgICBlY2hvID0gRkFMU0UsICMgc2hvdyBhbGwgb2YgdGhlIGNvZGUKICAgIHRpZHkgPSBGQUxTRSwgIyBjbGVhbmVyIGNvZGUgcHJpbnRpbmcKICAgIHNpemUgPSAic21hbGwiLCAjIHNtYWxsZXIgY29kZQogICAgCiAgICBmaWcucGF0aCA9ICJmaWdzLyIsIyB3aGVyZSB0aGUgZmlndXJlcyB3aWxsIGVuZCB1cAogICAgb3V0LndpZHRoID0gIjEwMCUiLAoKICAgIG1lc3NhZ2UgPSBGQUxTRSwKICAgIHdhcm5pbmcgPSBGQUxTRQogICAgKQpgYGAKCmBgYHtyIGluY2x1ZGU9RkFMU0V9CiMgcnVuIHRoZSBpbXBvcnQvY2xlYW4gc2NyaXB0CnNvdXJjZSgiZ2xvYmFsLlIiKQpgYGAKCiMgRXhwbG9yYXRvcnkgRGF0YSBBbmFseXNpcyAoRURBKQoKIyMgUGlhbm8gcHJhY3RpY2UgdGltZWxpbmUKCmBgYHtyIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTE1fQpyYXdfZGF0YSU+JQogIGdyb3VwX2J5KE1vbnRoX2Zvcm1hdCklPiUKICBzdW1tYXJpc2UoVG90YWxfRHVyYXRpb24gPSBzdW0oRHVyYXRpb24pLzYwKSU+JQogIG11dGF0ZShUb3RhbF9EdXJhdGlvbjIgPSBhcy5pbnRlZ2VyKGN1bXN1bShUb3RhbF9EdXJhdGlvbikpLAogICAgICAgICBtYXggPSBhcy5pbnRlZ2VyKG1heChUb3RhbF9EdXJhdGlvbjIpKSwKICAgICAgICAgbWF4ID0gaWZlbHNlKG1heCA+IFRvdGFsX0R1cmF0aW9uMiwgIiIsIG1heCkpJT4lCgogIGdncGxvdChhZXMoTW9udGhfZm9ybWF0LCBUb3RhbF9EdXJhdGlvbjIsIGdyb3VwID0gMSkpKwogIGdlb21fbGluZShzaXplID0gMiwgY29sb3IgPSAiIzY5YjNhMiIpKwogIGdlb21fcG9pbnQoc2l6ZSA9IDUsIGNvbG9yID0gIiM2OWIzYTIiKSsKICBnZW9tX2FyZWEoYWxwaGEgPSAwLjMsIGZpbGwgPSAiIzY5YjNhMiIpKwogICMgZ3JhZGUgMwogIGdlb21fcG9pbnQoeD0iT2N0XG4gJzE4IiwgeSA9IDI1Mywgc2l6ZSA9IDUsIGNvbG9yID0gImRhcmsgcmVkIikrCiAgZ2VvbV90ZXh0KHg9Ik9jdFxuICcxOCIsIHkgPSAyNTMrMjAwLCBzaXplID0gNSwgbGFiZWwgPSAiR3JhZGUgMyIpKwogIGdlb21fdGV4dCh4PSJPY3RcbiAnMTgiLCB5ID0gMjUzKzEwMCwgIHNpemUgPSA1LCBsYWJlbCA9ICIyNTMgaG91cnMiKSsKICAjIGdyYWRlIDUKICBnZW9tX3BvaW50KHg9Ik9jdFxuICcxOSIsIHkgPSA2NzUsIHNpemUgPSA1LCBjb2xvciA9ICJkYXJrIHJlZCIpKwogIGdlb21fdGV4dCh4PSJPY3RcbiAnMTkiLCB5ID0gNjc1KzIwMCwgIHNpemUgPSA1LCBsYWJlbCA9ICJHcmFkZSA1IikrCiAgZ2VvbV90ZXh0KHg9Ik9jdFxuICcxOSIsIHkgPSA2NzUrMTAwLCAgc2l6ZSA9IDUsIGxhYmVsID0gIjY3NSBob3VycyIpKwogICMgZ3JhZGUgNgogIGdlb21fcG9pbnQoeD0iT2N0XG4gJzIwIiwgeSA9IDEwNzgsIHNpemUgPSA1LCBjb2xvciA9ICJkYXJrIHJlZCIpKwogIGdlb21fdGV4dCh4PSJPY3RcbiAnMjAiLCB5ID0gMTA3OCsyMDAsICBzaXplID0gNSwgbGFiZWwgPSAiR3JhZGUgNiIpKwogIGdlb21fdGV4dCh4PSJPY3RcbiAnMjAiLCB5ID0gMTA3OCsxMDAsICBzaXplID0gNSwgbGFiZWwgPSAiMTA3OCBob3VycyIpKwogICMgTk9XCiAgZ2VvbV9wb2ludChhZXMoeD0iQXByXG4gJzIxIiwgeSA9IDEyMTkpLCBzaXplID0gNSwgY29sb3IgPSAiZGFyayByZWQiKSsKICBnZW9tX3RleHQoYWVzKGxhYmVsID0gbWF4KSwgbnVkZ2VfeSA9IDc1LCBudWRnZV94ID0gLTAuNSwgc2l6ZSA9IDUpKwogIHNjYWxlX2ZpbGxfZ3JhZGllbnQobG93PSJ5ZWxsb3ciLCBoaWdoPSJyZWQiKSsKICBsYWJzKHggPSBOVUxMLAogICAgICAgeSA9ICJUb3RhbCBob3VycyBvZiBwcmFjdGljZSIsCiAgICAgICB0aXRsZSA9ICJQaWFubyBwcmFjdGljZSB0aW1lbGluZSIpKwogIHRoZW1lX2lwc3VtX2VzKCkrCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIpCmBgYAoKIyMgSG93IGxvbmcgZGlkIEkgcHJhY3RpY2UgcGVyIHBpZWNlPwoKQmFzZWQgb24gdGhlIGxldmVsIGF0IHRoZSB0aW1lIGFuZCB0aGUgZGlmZmljdWx0eSBvZiB0aGUgcGllY2UsIHdlIGNhbiBzZWUgdGhhdCBlYWNoIHBpZWNlIHRvb2sgYXJvdW5kIDEwLTMwIGhvdXJzIG9mIHByYWN0aWNlLgoKYGBge3IgdGltZWxpbmV9CnJhd19kYXRhJT4lCiAgZmlsdGVyKERhdGVfU3RhcnQgPiBhcy5EYXRlKCIyMDE4LzExLzAxIikpJT4lCiAgZmlsdGVyKENvbXBsZXRlZCA9PSAiWWVzIiklPiUKICBncm91cF9ieShQcm9qZWN0LCBEYXRlX1N0YXJ0KSU+JQogIHN1bW1hcmlzZShEdXJhdGlvbiA9IHN1bShEdXJhdGlvbikvNjApJT4lCiAgbXV0YXRlKEN1bXVsYXRpdmVfUGllY2UgPSBjdW1zdW0oRHVyYXRpb24pLAogICAgICAgICBNb250aF9ZZWFyID0gYXMuZmFjdG9yKGFzLnllYXJtb24oRGF0ZV9TdGFydCkpLAogICAgICAgICBNb250aF9mb3JtYXQgPSBzdHJfcmVwbGFjZShNb250aF9ZZWFyLCAiIDIwIiwgIlxuICciKSklPiUKICB1bmdyb3VwKCklPiUKICBtdXRhdGUoQ3VtdWxhdGl2ZV9Ub3RhbCA9IGN1bXN1bShEdXJhdGlvbikpJT4lCiAgZmlsdGVyKFByb2plY3QgJW5vdGluJSBjKCJUZWNobmlxdWUiLCAiR2VuZXJhbCIsICJTaWdodHJlYWRpbmciKSklPiUKICBsZWZ0X2pvaW4obW9kZWxfZGF0YSU+JXNlbGVjdChMZXZlbCwgUHJvamVjdCwgQUJSU00pLCBieSA9ICJQcm9qZWN0IiklPiUKICAKZ2dwbG90KGFlcyhEYXRlX1N0YXJ0LCBDdW11bGF0aXZlX1BpZWNlLCBmaWxsID0gTGV2ZWwpKSArCiAgZ2VvbV9wb2ludChzaXplID0gMTAsIHNoYXBlID0gMjEsIGNvbCA9ICJibGFjayIsIGFscGhhID0gMC41KSArCiAgc2NhbGVfc2l6ZShyYW5nZSA9IGMoLjEsIDE2KSwgZ3VpZGUgPSBGQUxTRSkgKwogIGxhYnModGl0bGUgPSAnWWVhcjoge2ZyYW1lX3RpbWV9JywKICAgICAgIHkgPSAiVG90YWwgcHJhY3RpY2UgdGltZSBwZXIgcGllY2UgKGhvdXJzKSIpKwogIHNjYWxlX2NvbG9yX3Ryb24oKSsKICBzY2FsZV9maWxsX3Ryb24oKSsKICB0aGVtZV9pcHN1bV9lcygpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIikrCiAgdHJhbnNpdGlvbl90aW1lKERhdGVfU3RhcnQpICsKICBlYXNlX2FlcygnbGluZWFyJykrCiAgZXhpdF9mYWRlKCkgKwogIHNoYWRvd19tYXJrKGFscGhhID0gMC4xLCBzaXplID0gNSkKCiMgc2F2ZSBhbmltYXRpb24gYXMgZ2lmIGZvciBsYXRlciB1c2UKIyBhbmltX3NhdmUoImZpZ3MvdGltZWxpbmUuZ2lmIikKYGBgCgojIyBIb3cgY29uc2lzdGVudCB3YXMgbXkgcHJhY3RpY2U/CgpHZW5lcmFsbHksIEkndmUgZG9uZSBwcmV0dHkgd2VsbCB0byBtYWludGFpbiBhIGhpZ2ggbGV2ZWwgb2YgY29uc2lzdGVuY3kgd2l0aCB0aGUgZXhjZXB0aW9uIG9mIEF1Z3VzdC9EZWNlbWJlci4gVGhpcyBpcyB1c3VhbGx5IHdoZXJlIEkgdGVuZCB0byB0YWtlIGFubnVhbCBsZWF2ZS4KCmBgYHtyIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTE1fQpyYXdfZGF0YSU+JQogIGZpbHRlcihTb3VyY2UgIT0gIkVzdGltYXRlZCIpJT4lCiAgZ3JvdXBfYnkoTW9udGhfWWVhciwgTW9udGhfU3RhcnQsIE1vbnRoX2Zvcm1hdCklPiUKICBzdW1tYXJpc2UoRGF5c19QcmFjdGljZSA9IG5fZGlzdGluY3QoRGF0ZV9TdGFydCksCiAgICAgICAgICAgIFRvdGFsX0R1cmF0aW9uID0gc3VtKER1cmF0aW9uLCBuYS5ybSA9IFRSVUUpKSU+JQogIG11dGF0ZShEYXlzX1RvdGFsID0gZGF5c19pbl9tb250aChNb250aF9TdGFydCksCiAgICAgICAgIERheXNfTm90X1ByYWN0aWNlZCA9IERheXNfVG90YWwgLSBEYXlzX1ByYWN0aWNlLAogICAgICAgICBBdmdfRHVyYXRpb24gPSBhcy5pbnRlZ2VyKFRvdGFsX0R1cmF0aW9uL0RheXNfVG90YWwpLAogICAgICAgICBDb25zaXN0ZW5jeSA9IHJvdW5kKERheXNfUHJhY3RpY2UgLyBEYXlzX1RvdGFsICogMTAwLDIpLAogICAgICAgICBDb25zaXN0ZW5jeV9TdGF0dXMgPSBpZmVsc2UoQ29uc2lzdGVuY3k8NzUsICJCYWQiLCAiR29vZCIpLAogICAgICAgICBNb250aF9mb3JtYXQgPSByZW9yZGVyKE1vbnRoX2Zvcm1hdCwgTW9udGhfWWVhcikpJT4lCiAgCiAgZ2dwbG90KGFlcyhNb250aF9mb3JtYXQsIENvbnNpc3RlbmN5LCBmaWxsID0gQ29uc2lzdGVuY3lfU3RhdHVzKSkrCiAgZ2VvbV9jb2woZ3JvdXAgPSAxLCBjb2wgPSAiYmxhY2siKSsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSA3NSwgbHR5ID0gImRhc2hlZCIpKwogIGdlb21fdGV4dChhZXMobGFiZWwgPSBEYXlzX05vdF9QcmFjdGljZWQpLCBzaXplID0gNSwgbnVkZ2VfeSA9IDMpKwogIGxhYnMoeCA9IE5VTEwsCiAgICAgICBmaWxsID0gIkNvbnNpc3RlbmN5IHN0YXR1cyIsCiAgICAgICBzdWJ0aXRsZSA9ICJOdW1iZXJzIGluZGljYXRlIGRheXMgd2l0aG91dCBhbnkgcHJhY3RpY2Ugd2l0aGluIGVhY2ggbW9udGgiKSsKICBzY2FsZV9jb2xvcl90cm9uKCkrCiAgc2NhbGVfZmlsbF90cm9uKCkrCiAgdGhlbWVfaXBzdW1fZXMoKSsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIikKYGBgCgojIyBXYXMgdGhlcmUgYSB0cmVuZCBpbiBteSBhbW91bnQgb2YgZGFpbHkgYXZlcmFnZSBwcmFjdGljZT8gey50YWJzZXQgLnRhYnNldC1mYWRlIC50YWJzZXQtcGlsbHN9CgpXZSBjYW4gc2VlIHRoYXQgbXkgcHJhY3RpY2UgdGltZSB3YXMgY29ycmVsYXRlZCB3aXRoIHRoZSBjb25zaXN0ZW5jeSwgd2hlcmUgdGhlIGF2ZXJhZ2Ugc2Vzc2lvbiB3YXMgbXVjaCBzaG9ydGVyIGluIHRoZSBtb250aHMgSSB3YXMgYXdheSBmcm9tIHRoZSBwaWFuby4gVGhlcmUncyBhbHNvIGEgdHJlbmQgd2hlcmUgbXkgcHJhY3RpY2UgY2xvc2UgdG8gYW4gZXhhbSBzZXNzaW9uIHdhcyBzaWduaWZpY2FudGx5IGhpZ2hlciB0aGFuIGFueSBvdGhlciB0aW1lIG9mIHRoZSB5ZWFyLiAqKkNhbiB5b3Ugc3BvdCBpbiB3aGljaCBtb250aCBJIGhhZCBteSBleGFtIGluIDIwMTk/IFdoYXQgYWJvdXQgdGhlIGVuZCBvZiAyMDIwPyoqCgoqYXZlcmFnZSBwcmFjdGljZSBsZW5ndGggcGVyIG1vbnRoIGluY2x1ZGVzIHRoZSBkYXlzIGluIHdoaWNoIEkgZGlkIG5vdCBwcmFjdGljZSoKCiMjIyBvdmVyYWxsIHstfQoKYGBge3IgZmlnLmhlaWdodD02LCBmaWcud2lkdGg9MTV9CnJhd19kYXRhJT4lCiAgZmlsdGVyKFNvdXJjZSAhPSAiRXN0aW1hdGVkIiklPiUKICBncm91cF9ieShNb250aF9ZZWFyLCBNb250aF9TdGFydCwgTW9udGhfZm9ybWF0KSU+JQogIHN1bW1hcmlzZShEYXlzX1ByYWN0aWNlID0gbl9kaXN0aW5jdChEYXRlX1N0YXJ0KSwKICAgICAgICAgICAgVG90YWxfRHVyYXRpb24gPSBzdW0oRHVyYXRpb24pKSU+JQogIG11dGF0ZShEYXlzX1RvdGFsID0gZGF5c19pbl9tb250aChNb250aF9TdGFydCksCiAgICAgICAgIEF2Z19EdXJhdGlvbiA9IGFzLmludGVnZXIoVG90YWxfRHVyYXRpb24vRGF5c19Ub3RhbCksCiAgICAgICAgIEF2Z19EdXJhdGlvbl9TdGF0dXMgPSBpZmVsc2UoQXZnX0R1cmF0aW9uIDwgNjAsICJMZXNzIHRoYW4gb25lIGhvdXIiLCAiT25lIGhvdXIiKSwKICAgICAgICAgTW9udGhfZm9ybWF0ID0gcmVvcmRlcihNb250aF9mb3JtYXQsIE1vbnRoX1llYXIpKSU+JQogIAogIGdncGxvdChhZXMoTW9udGhfZm9ybWF0LCBBdmdfRHVyYXRpb24sIGZpbGwgPSBBdmdfRHVyYXRpb25fU3RhdHVzKSkrCiAgZ2VvbV9jb2woY29sID0gImJsYWNrIikrCiAgbGFicyh4ID0gTlVMTCwKICAgICAgIHkgPSAiQXZlcmFnZSBwcmFjdGljZSBzZXNzaW9uIGxlbmd0aCAobWluKSIsCiAgICAgICBmaWxsID0gIlN0YXR1cyIpKwogIGdlb21fdGV4dChhZXMobGFiZWwgPSBBdmdfRHVyYXRpb24pLCBudWRnZV95ID0gNSwgc2l6ZSA9IDUpKwogIHNjYWxlX2NvbG9yX3Ryb24oKSsKICBzY2FsZV9maWxsX3Ryb24oKSsKICB0aGVtZV9pcHN1bV9lcygpKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiLAogICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGlja3MueSA9IGVsZW1lbnRfYmxhbmsoKSkKYGBgCgojIyMgWWVhciBvbiBZZWFyIHstfQoKU2ltaWxhciB0cmVuZHMgYXMgYmVmb3JlIGFyZSBhcHBhcmVudCB3aGVyZSBteSBhdmVyYWdlIGRhaWx5IHNlc3Npb24gaXMgbG9uZ2VyIGJlZm9yZSB0aGUgZXhhbXMgdGhhbiBhbnkgb3RoZXIgdGltZSBpbiB0aGUgeWVhciBhbmQgYSBkaXAgaW4gdGhlIG1vbnRocyB3aGVyZSBJIHVzdWFsbHkgdGFrZSBtb3N0IG9mIG15IGFubnVhbCBsZWF2ZS4gSSByZWFsbHkgZG8gbmVlZCB0byBzdGFydCBwaWNraW5nIHVwIHRoZSBwYWNlIGFuZCBnZXQgYmFjayB0byB3aGVyZSBJIHVzZWQgdG8gYmUuCgpgYGB7ciBmaWcuaGVpZ2h0PTYsIGZpZy53aWR0aD0xNX0KcmF3X2RhdGElPiUKICBncm91cF9ieShNb250aF9ZZWFyLCBNb250aF9TdGFydCwgTW9udGhfZm9ybWF0LCBNb250aF9OYW1lLCBZZWFyKSU+JQogIHN1bW1hcmlzZShEYXlzX1ByYWN0aWNlID0gbl9kaXN0aW5jdChEYXRlX1N0YXJ0KSwKICAgICAgICAgICAgVG90YWxfRHVyYXRpb24gPSBzdW0oRHVyYXRpb24pKSU+JQogIG11dGF0ZShEYXlzX1RvdGFsID0gZGF5c19pbl9tb250aChNb250aF9TdGFydCksCiAgICAgICAgIEF2Z19EdXJhdGlvbiA9IGFzLmludGVnZXIoVG90YWxfRHVyYXRpb24vRGF5c19Ub3RhbCksCiAgICAgICAgIEF2Z19EdXJhdGlvbl9TdGF0dXMgPSBpZmVsc2UoQXZnX0R1cmF0aW9uIDwgNjAsICJMZXNzIHRoYW4gb25lIGhvdXIiLCAiT25lIGhvdXIiKSwKICAgICAgICAgTW9udGhfZm9ybWF0ID0gcmVvcmRlcihNb250aF9mb3JtYXQsIE1vbnRoX1llYXIpLAogICAgICAgICBzaXplID0gYXMuZmFjdG9yKGlmZWxzZShZZWFyID09IDIwMTgsIDEsIDEuNSkpLAogICAgICAgICBsYWJlbCA9IGlmZWxzZShtb250aChNb250aF9TdGFydCkgPT0gMSwgYXMuY2hhcmFjdGVyKFllYXIpLCAiIikpJT4lCiAgCiAgZ2dwbG90KGFlcyhNb250aF9OYW1lLCBBdmdfRHVyYXRpb24sIGdyb3VwID0gWWVhciwgc2l6ZSA9IHNpemUpKSsKICBnZW9tX2xpbmUoYWVzKGNvbCA9IFllYXIpKSsKICBnZW9tX2xhYmVsX3JlcGVsKGFlcyhsYWJlbCA9IGxhYmVsLCBjb2wgPSBZZWFyKSkrCiAgbGFicyh4ID0gTlVMTCwKICAgICAgIGZpbGwgPSAiU3RhdHVzIikrCiAgc2NhbGVfY29sb3JfdHJvbigpKwogIHNjYWxlX2ZpbGxfdHJvbigpKwogIHRoZW1lX2lwc3VtX2VzKCkrCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQpgYGAKCiMjIERpZCBDT1ZJRCBzaWduaWZpY2FudGx5IGltcGFjdCBteSBwcmFjdGljZSB0aW1lPyB7LnRhYnNldCAudGFic2V0LWZhZGUgLnRhYnNldC1waWxsc30KCiMjIyBncmFwaCB7LX0KCkRlc3BpdGUgYSBzaW1pbGFyIG1lZGlhbiwgd2UgY2FuIHNlZSB0aGF0IHRoZSBwcmFjdGljZSBzZXNzaW9ucyB3ZXJlIGxlc3MgbGlrZWx5IHRvIGJlIG92ZXIgODAgbWluIGFmdGVyIENPVklELiBXZSBjYW4gdGVzdCBpZiB0aGlzIHdhcyBhIHNpZ25pZmljYW50IGltcGFjdCB3aXRoIGEgdC10ZXN0LgoKYGBge3IgZmlnLmhlaWdodD01LCBmaWcud2lkdGg9OX0KY292aWRfc3RhcnQgPC0gYXMuRGF0ZSgiMjAyMC8wMy8yMyIpCgppbmZlcmVuY2UgPC0gcmF3X2RhdGElPiUKICBmaWx0ZXIoU291cmNlICE9ICJFc3RpbWF0ZWQiKSU+JQogIG11dGF0ZShDb3ZpZF9TdGF0dXMgPSBhcy5mYWN0b3IoaWZlbHNlKERhdGVfU3RhcnQgPCBjb3ZpZF9zdGFydCwgIkJlZm9yZSBDT1ZJRCIsICJBZnRlciBDT1ZJRCIpKSwKICAgICAgICAgQ292aWRfU3RhdHVzID0gcmVvcmRlcihDb3ZpZF9TdGF0dXMsIGRlc2MoQ292aWRfU3RhdHVzKSkpJT4lCiAgZ3JvdXBfYnkoQ292aWRfU3RhdHVzLCBEYXRlX1N0YXJ0KSU+JQogIHN1bW1hcmlzZShEdXJhdGlvbiA9IHN1bShEdXJhdGlvbikpJT4lCiAgdW5ncm91cCgpCiAgCiAgZ2dwbG90KGluZmVyZW5jZSwgYWVzKENvdmlkX1N0YXR1cywgRHVyYXRpb24sIGZpbGwgPSBDb3ZpZF9TdGF0dXMpKSsKICBnZW9tX2JveHBsb3QodmFyd2lkdGggPSBUUlVFLCBjb2wgPSAiYmxhY2siKSsKICBsYWJzKHggPSBOVUxMLAogICAgICAgeSA9ICJBdmVyYWdlIHByYWN0aWNlIHNlc3Npb24gKG1pbikiKSsKICBzY2FsZV9jb2xvcl90cm9uKCkrCiAgc2NhbGVfZmlsbF90cm9uKCkrCiAgdGhlbWVfaXBzdW1fZXMoKSsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpCmBgYAoKIyMjIHNrZXduZXNzIGFzc3VtcHRpb24gey19CgpHaXZlbiB0aGUgZXh0cmVtZWx5IGxvdyBwLXZhbHVlLCB0aGUgU2hhcGlyby1XaWxrIG5vcm1hbGl0eSB0ZXN0IGltcGxpZXMgdGhhdCB0aGUgZGlzdHJpYnV0aW9uIG9mIHRoZSBkYXRhIGlzIHNpZ25pZmljYW50bHkgZGlmZmVyZW50IGZyb20gYSBub3JtYWwgZGlzdHJpYnV0aW9uIGFuZCB0aGF0IHdlIGNhbm5vdCBhc3N1bWUgdGhlIG5vcm1hbGl0eS4gSG93ZXZlciwgd2UncmUgd29ya2luZyB3aXRoIHRoZSBlbnRpcmUgcG9wdWxhdGlvbiBkYXRhc2V0IGZvciBlYWNoIGNsYXNzIGFuZCB0aHVzLCB1bmxpa2UgdGhlIGluZGVwZW5kZW5jZSBvZiBkYXRhLCB0aGlzIGFzc3VtcHRpb24gaXMgbm90IGNydWNpYWwuCiAgCmBgYHtyfQogIGluZmVyZW5jZSAlPiUgCiAgc2VsZWN0KENvdmlkX1N0YXR1cywgRHVyYXRpb24pICU+JSAKICBncm91cF9ieShncm91cCA9IGFzLmNoYXJhY3RlcihDb3ZpZF9TdGF0dXMpKSAlPiUKICBkbyh0aWR5KHNoYXBpcm8udGVzdCguJER1cmF0aW9uKSkpJT4lCiAga2JsKGNhcHRpb24gPSAiU2hhcGlyby1XaWxrIG5vcm1hbGl0eSB0ZXN0IiklPiUKICBrYWJsZV9wYXBlcigiaG92ZXIiLCBmdWxsX3dpZHRoID0gRikKCmBgYAoKIyMjIGVxdWFsIHZhcmlhbmNlcyBhc3N1bXB0aW9uIHstfQoKV2UgY2FuIHNlZSB0aGF0IHdpdGggYSBsYXJnZSBwIHZhbHVlLCB3ZSBzaG91bGQgZmFpbCB0byByZWplY3QgdGhlIE51bGwgaHlwb3RoZXNpcyAoSG8pIGFuZCBjb25jbHVkZSB0aGF0IHdlIGRvIG5vdCBoYXZlIGV2aWRlbmNlIHRvIGJlbGlldmUgdGhhdCBwb3B1bGF0aW9uIHZhcmlhbmNlcyBhcmUgbm90IGVxdWFsIGFuZCB1c2UgdGhlIGVxdWFsIHZhcmlhbmNlcyBhc3N1bXB0aW9uIGZvciBvdXIgdCB0ZXN0CgpgYGB7cn0KdGlkeShsZXZlbmVUZXN0KGluZmVyZW5jZSREdXJhdGlvbn5pbmZlcmVuY2UkQ292aWRfU3RhdHVzKSklPiUKICBrYmwoY2FwdGlvbiA9ICJMZXZlbmUncyB0ZXN0IiklPiUKICBrYWJsZV9wYXBlcigiaG92ZXIiLCBmdWxsX3dpZHRoID0gRikKYGBgCgojIyMgdC10ZXN0IHstfQoKTXkgcHJhY3RpY2Ugc2Vzc2lvbnMgcG9zdC1DT1ZJRCBhcmUgc2lnbmlmaWNhbnRseSBzaG9ydGVyIHRoYW4gdGhvc2UgYmVmb3JlIHRoZSBwYW5kZW1pYy4gVGhpcyBtaWdodCBiZSBzdXJwcmlzaW5nLCBnaXZlbiB0aGF0IHdlIHdlcmUgaW4gdGhlIGxvY2tkb3duIG1vc3Qgb2YgdGhlIHRpbWUuIEhvd2V2ZXIsIEkndmUgYmVlbiBzcGVuZGluZyBteSB0aW1lIGRvaW5nIGEgZmV3IG90aGVyIHRoaW5ncyBzdWNoIGFzIGltcHJvdmluZyBteSB0ZWNobmljYWwgc2tpbGxzZXQgd2l0aCBSICh0aGlzIGFuYWx5c2lzIHdvdWxkbid0IGhhdmUgYmVlbiBwb3NzaWJsZSBvdGhlcndpc2UpIGFuZCBsZWFybmluZyBpdGFsaWFuLgoKYGBge3J9CnRfdGVzdCA8LSBpbmZlcmVuY2UlPiUKICB0X3Rlc3QoRHVyYXRpb24gfiBDb3ZpZF9TdGF0dXMsIHZhci5lcXVhbCA9IFRSVUUpJT4lCiAgYWRkX3NpZ25pZmljYW5jZSgpJT4lCiAga2JsKCklPiUKICBrYWJsZV9wYXBlcigiaG92ZXIiLCBmdWxsX3dpZHRoID0gRikKCnRfdGVzdApgYGAKCiMjIFdoYXQgdHlwZSBvZiBtdXNpYyBkbyBJIHRlbmQgdG8gcGxheT8gey50YWJzZXQgLnRhYnNldC1mYWRlIC50YWJzZXQtcGlsbHN9CgojIyMgYnkgZ2VucmUgey19CgpgYGB7cn0KZ3JhcGhfcHJhY3RpY2UgPC0gZnVuY3Rpb24odmFyaWFibGUsIG51ZGdlKXsKICByYXdfZGF0YSU+JQogIGZpbHRlcihHZW5yZSAlbm90aW4lIGMoIk90aGVyIiwgIk5vdCBhcHBsaWNhYmxlIikpJT4lCiAgZ3JvdXBfYnkoe3t2YXJpYWJsZX19KSU+JQogIHN1bW1hcmlzZShEdXJhdGlvbiA9IGFzLmludGVnZXIoc3VtKER1cmF0aW9uKS82MCkpJT4lCiAgYXJyYW5nZShkZXNjKER1cmF0aW9uKSklPiUKICBoZWFkKDEwKSU+JQoKICBnZ3Bsb3QoYWVzKHJlb3JkZXIoe3t2YXJpYWJsZX19LCBEdXJhdGlvbiksIER1cmF0aW9uLCBmaWxsID0gRHVyYXRpb24pKSsKICBnZW9tX2NvbChzaG93LmxlZ2VuZCA9IEZBTFNFLCBjb2wgPSAiYmxhY2siLCB3aWR0aCA9IDEpKwogIGdlb21fdGV4dChhZXMobGFiZWwgPSBEdXJhdGlvbiksIHNob3cubGVnZW5kID0gRkFMU0UsIG51ZGdlX3kgPSBudWRnZSwgc2l6ZSA9IDUpKwogIHNjYWxlX2ZpbGxfZ3JhZGllbnQobG93PSJ5ZWxsb3ciLCBoaWdoPSJyZWQiKSsKICBsYWJzKHggPSBOVUxMLAogICAgICAgeSA9ICJUb3RhbCBob3VycyBvZiBwcmFjdGljZSIpKwogIGNvb3JkX2ZsaXAoKSsKICB0aGVtZV9pcHN1bV9lcygpKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGlja3MgPSBlbGVtZW50X2JsYW5rKCkpCn0KCmdyYXBoX3ByYWN0aWNlKEdlbnJlLCAxNSkKYGBgCgojIyMgYnkgY29tcG9zZXIgey19CgpgYGB7cn0KZ3JhcGhfcHJhY3RpY2UoQ29tcG9zZXIsIDUpCmBgYAoKIyMjIGJ5IHBpZWNlIHstfQoKYGBge3J9CmdyYXBoX3ByYWN0aWNlKFByb2plY3QsIDMpCmBgYAoKIyMgUmVsYXRpb24gYmV0d2VlbiBkaWZmaWN1bHR5IGFuZCBudW1iZXIgb2YgcHJhY3RpY2UgaG91cnMgey50YWJzZXQgLnRhYnNldC1mYWRlIC50YWJzZXQtcGlsbHN9CgojIyMgQUJSU00gZ3JhZGUgey19CgpTaW1wbGlmaWVkLCBBQkJSU00gZ3JhZGVzIGFyZSBhIGdyb3VwIG9mIDggZXhhbXMgYmFzZWQgb24gdGhlaXIgZGlmZmljdWx0eSAoMSAtIGJlZ2lubmVyIHRvIDggLSBhZHZhbmNlZCkuIFRoZXJlIGFyZSBhbHNvIGRpcGxvbWEgZ3JhZGVzIGJ1dCB0aG9zZSBhcmUgZXh0cmVtZWx5IGFkdmFuY2VkLCBlcXVpdmFsZW50IHRvIHVuaXZlcnNpdHkgbGV2ZWwgc3R1ZGllcyBhbmQgb3V0IG9mIHRoZSBzY29wZSBvZiB0aGlzIGFuYWx5c2lzLiAKCk1vcmUgaW5mb3JtYXRpb24gY2FuIGJlIGZvdW5kIG9uIHRoZWlyIG9mZmljaWFsIHdlYnNpdGUgYXQgaHR0cHM6Ly9nYi5hYnJzbS5vcmcvZW4vZXhhbS1zdXBwb3J0L3lvdXItZ3VpZGUtdG8tYWJyc20tZXhhbXMvCgpgYGB7cn0KbW9kZWxfZGF0YSU+JQogIG11dGF0ZShEdXJhdGlvbiA9IER1cmF0aW9uKSU+JQogIAogIGdncGxvdChhZXMoQUJSU00sIER1cmF0aW9uLCBmaWxsID0gQUJSU00pKSsKICBnZW9tX2JveHBsb3QodmFyd2lkdGggPSBUUlVFLCBvdXRsaWVyLmNvbG91ciA9ICJyZWQiKSsKICBsYWJzKHggPSAiQUJSU00gR3JhZGUiLAogICAgICAgeSA9ICJUb3RhbCBwcmFjdGljZSBob3VycyIsCiAgICAgICBzdWJ0aXRsZSA9ICJUaGUgaGlnaGVyIHRoZSBkaWZmaWN1bHR5LCB0aGUgbW9yZSB0aW1lIGl0IHRha2VzIHRvIGxlYXJuIGEgcGllY2UiKSsKICBzY2FsZV9jb2xvcl90cm9uKCkrCiAgc2NhbGVfZmlsbF90cm9uKCkrCiAgdGhlbWVfaXBzdW1fZXMoKSsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpCmBgYAoKIyMjIGxldmVsIHstfQoKQSBmdXJ0aGVyIGFnZ3JlZ2F0aW9uIG9mIEFCUlNNIGdyYWRlczsgdGhpcyBpcyBoZWxwZnVsIGdpdmVuIHRoZSB2ZXJ5IGxpbWl0ZWQgZGF0YXNldCB3aXRoaW4gZWFjaCBncmFkZSBhbmQgbXVjaCBlYXNpZXIgb24gdGhlIGV5ZS4gVGhpcyBpcyBhbiBvdmVyc2ltcGxpZmljYXRpb24gYnV0IHRoZXkncmUgY2xhc3NpZmllZCBhczoKICAqIDEtNTogQmVnaW5uZXIgKDEpCiAgKiA1LTY6IEludGVybWVkaWF0ZSAoMikKICAqIDctODogQWR2YW5jZWQgKDMpCgpgYGB7cn0KbW9kZWxfZGF0YSU+JQogIG11dGF0ZShEdXJhdGlvbiA9IER1cmF0aW9uKSU+JQogIAogIGdncGxvdChhZXMoTGV2ZWwsIER1cmF0aW9uLCBmaWxsID0gTGV2ZWwpKSsKICBnZW9tX2JveHBsb3QodmFyd2lkdGggPSBUUlVFLCBvdXRsaWVyLmNvbG91ciA9ICJyZWQiKSsKICBzY2FsZV9jb2xvcl90cm9uKCkrCiAgc2NhbGVfZmlsbF90cm9uKCkrCiAgbGFicyh4ID0gIkxldmVsIiwKICAgICAgIHkgPSAiVG90YWwgcHJhY3RpY2UgaG91cnMiLAogICAgICAgc3VidGl0bGUgPSAiVGhlIGhpZ2hlciB0aGUgZGlmZmljdWx0eSwgdGhlIG1vcmUgdGltZSBpdCB0YWtlcyB0byBsZWFybiBhIHBpZWNlIikrCiAgdGhlbWVfaXBzdW1fZXMoKSsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpCmBgYAoKIyMgV2hhdCBhYm91dCB0aGUgcGllY2UgbGVuZ3RoPwoKYGBge3J9Cm1vZGVsX2RhdGElPiUKICAKICBnZ3Bsb3QoYWVzKExlbmd0aCwgRHVyYXRpb24sIGdyb3VwID0gMSkpKwogIGdlb21faml0dGVyKGFlcyhjb2wgPSBMZXZlbCksIHdpZHRoID0gMC41LCBoZWlnaHQgPSAwLjUsIHNpemUgPSAzKSsKICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBzZT1GQUxTRSkrCiAgbGFicyh4ID0gIlBpZWNlIGxlbmd0aCAobWlucykiLAogICAgICAgeSA9ICJIb3VycyBuZWVkZWQgdG8gbGVhcm4gYSBwaWVjZSIsCiAgICAgICBzdWJ0aXRsZSA9ICJUaGVyZSBhcHBlYXJzIHRvIGJlIGEgbGluZWFyIHRyZW5kIGJldHdlZW4gcGllY2UgbGVuZ3RoIGFuZCB0b3RhbCBwcmFjdGljZSB0aW1lIikrCiAgc2NhbGVfY29sb3JfdHJvbigpKwogIHNjYWxlX2ZpbGxfdHJvbigpKwogIHRoZW1lX2lwc3VtX2VzKCkrCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIpCmBgYAoKIyMgTGVhcm5pbmcgZWZmZWN0IC0gZG8gcGllY2VzIG9mIHRoZSBzYW1lIGRpZmZpY3VsdHkgYmVjb21lIGVhc2llciB0byBsZWFybiB3aXRoIHRpbWU/CgpXZSBjYW4gc3BvdCBhIHRyZW5kIHdoZXJlIHRoZSB0aW1lIHJlcXVpcmVkIHRvIGxlYXJuIGEgcGllY2Ugb2YgYSBzaW1pbGFyIGRpZmZpY3VsdHkgKEFCUlNNIEdyYWRlKSBkZWNyZWFzZXMgYXMgbXkgYWJpbGl0eSB0byBwbGF5IHRoZSBwaWFubyBpbmNyZWFzZXMgKGFzIGp1ZGdlZCBieSBjdW11bGF0aXZlIGhvdXJzIG9mIHByYWN0aWNlKS4gV2Ugc2hvdWxkIGtlZXAgdGhpcyBpbiBtaW5kIGFuZCBpbmNsdWRlIGl0IGFzIGEgdmFyaWFibGUgaW50byBvdXIgcHJlZGljdGlvbiBtb2RlbC4KCmBgYHtyfQptb2RlbF9kYXRhJT4lCiAgCiAgZ2dwbG90KGFlcyhDdW11bGF0aXZlX0R1cmF0aW9uLCBEdXJhdGlvbiwgZ3JvdXAgPSAxKSkrCiAgZ2VvbV9wb2ludChhZXMoY29sID0gTGV2ZWwpLCBzaXplID0gMykrCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgc2U9RkFMU0UpKwogIGxhYnMoeCA9ICJDdW11bGF0aXZlIGhvdXJzIHByYWN0aWNlZCBiZWZvcmUgdGhlIGZpcnN0IHByYWN0aWNlIG9mIGVhY2ggcGllY2UiLAogICAgICAgeSA9ICJIb3VycyBuZWVkZWQgdG8gbGVhcm4gYSBwaWVjZSIsCiAgICAgICBzdWJ0aXRsZSA9ICJQaWVjZXMgb2YgYSBzaW1pbGFyIGRpZmZpY3VsdHkgYmVjb21lIGZhc3RlciB0byBsZWFybiIpKwogIHNjYWxlX2NvbG9yX3Ryb24oKSsKICBzY2FsZV9maWxsX3Ryb24oKSsKICB0aGVtZV9pcHN1bV9lcygpKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiKQpgYGAKCiMjIERvZXMgInBhdXNpbmciIGEgcGllY2UgaW1wYWN0IHRoZSB0b3RhbCB0aW1lIHJlcXVpcmVkIHRvIGxlYXJuIGl0PwoKSG93IGRvIHdlIGRpZmZlcmVudGlhdGUgYmV0d2VlbiBwaWVjZXMgdGhhdCB3ZSBsZWFybiBvbmNlIGFuZCB0aG9zZSB0aGF0IHdlIGNvbWUgYmFjayB0byByZXBlYXRlZGx5PyBFeGFtcGxlcyBjb3VsZCBpbmNsdWRlIHdhbnRpbmcgdG8gaW1wcm92ZSB0aGUgcGxheWluZyBmdXJ0aGVyLCBsb3ZpbmcgaXQgc28gbXVjaCB3ZSB3YW50ZWQgdG8gcmVsZWFybiBpdCwgcHJlcGFyaW5nIGl0IGZvciBhIG5ldyBwZXJmb3JtYW5jZSwgZXRjLgoKQXMgYW55b25lIHRoYXQgZXZlciBwbGF5ZWQgdGhlIHBpYW5vIGtub3dzLCByZS1sZWFybmluZyBhIHBpZWNlLCBwYXJ0aWN1bGFybHkgYWZ0ZXIgeW91ICJkcm9wIiBpdCBmb3IgYSBmZXcgbW9udGhzL3llYXJzLCByZXN1bHRzIGluIGEgbXVjaCBiZXR0ZXIgcGVyZm9ybWFuY2UvdW5kZXJzdGFuZGluZyBvZiB0aGUgcGllY2UuIEkgZGVmaW5pdGVseSBmb3VuZCB0aGF0IHRvIGJlIHRydWUgaW4gbXkgZXhwZXJpZW5jZSwgcGFydGljdWxhcmx5IHdpdGggbXkgZXhhbSBwaWVjZXMuVGhlIGRvd25zaWRlIGlzIHRoYXQgdGhlc2UgcGllY2VzIHRha2UgbG9uZ2VyIHRvIGxlYXJuLgoKYGBge3Igd2lkdGggPSAxM30KbW9kZWxfZGF0YSU+JQogIG11dGF0ZShQcm9qZWN0X2Zvcm1hdHRlZCA9IHN0cl9yZXBsYWNlX2FsbChQcm9qZWN0LCJbXls6Z3JhcGg6XV0iLCAiICIpLAogICAgICAgICBQcm9qZWN0X2xhYmVsID0gYXMuZmFjdG9yKGlmZWxzZShNYXhfQnJlYWsgPiAzMSwgUHJvamVjdF9mb3JtYXR0ZWQsICIiKSkpJT4lCiAgCiAgZ2dwbG90KGFlcyhhcy5pbnRlZ2VyKE1heF9CcmVhayksIER1cmF0aW9uLCBjb2wgPSBNYXhfQnJlYWsgPD0gMzEpKSsKICBnZW9tX3BvaW50KHNpemUgPSAzKSsKICBnZW9tX3RleHRfcmVwZWwoYWVzKGxhYmVsID0gUHJvamVjdF9sYWJlbCksIHNpemUgPSAzLCBzaG93LmxlZ2VuZCA9IEZBTFNFKSsKICBzY2FsZV94X2xvZzEwKCkrCiAgc2NhbGVfY29sb3JfdHJvbihsYWJlbHMgPSBjKFRSVUUsIEZBTFNFKSkrCiAgZ3VpZGVzKGNvbG91ciA9IGd1aWRlX2xlZ2VuZChyZXZlcnNlPVRSVUUpKSsKICBsYWJzKHggPSAiTWF4aW11bSBkYXlzIHBhc3NlZCBiZXR3ZWVuIHR3byBjb25zZWN1dGl2ZSBzZXNzaW9ucyBvbiB0aGUgc2FtZSBwaWVjZSAobG9nIHNjYWxlKSIsCiAgICAgICB5ID0gIkhvdXJzIG5lZWRlZCB0byBsZWFybiBhIHBpZWNlIiwKICAgICAgIGNvbCA9ICJCcmVhayAob3ZlciAxIG1vbnRoKSIsCiAgICAgICBzdWJ0aXRsZSA9ICJUYWtpbmcgYSBicmVhayBiZWZvcmUgZmluaXNoaW5nIGEgcGllY2UgbWlnaHQgbGVhZCB0byBtb3JlIGhvdXJzIHJlcXVpcmVkIHRvIGxlYXJuIGl0IikrCiAgdGhlbWVfaXBzdW1fZXMoKSsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIikKYGBgCgojIyBSZXBlcnRvaXJlCgpgYGB7cn0KbW9kZWxfZGF0YSU+JQogIHNlbGVjdCgtRGF5c19QcmFjdGljZWQsIC1EYXRlX0VuZCwgLU1heF9CcmVhayklPiUKICBtdXRhdGUoRHVyYXRpb24gPSByb3VuZChEdXJhdGlvbiksCiAgICAgICAgIExlbmd0aCA9IHJvdW5kKExlbmd0aCwgMSkpJT4lCiAgYXJyYW5nZShkZXNjKERhdGVfU3RhcnQpKSU+JQogIHJlbmFtZShFeHBlcmllbmNlID0gQ3VtdWxhdGl2ZV9EdXJhdGlvbiwKICAgICAgICAgU3RhcnRlZCA9IERhdGVfU3RhcnQpJT4lCiAgcmVsb2NhdGUoUHJvamVjdCwgRHVyYXRpb24sIEdlbnJlLCBBQlJTTSwgTGV2ZWwsIFN0YW5kYXJkLCBMZW5ndGgsIEV4cGVyaWVuY2UsIEJyZWFrLCBTdGFydGVkKSU+JQogIAogIGtibChlc2NhcGUgPSBGQUxTRSxjYXB0aW9uID0gIlJlcGVydG9pcmUiKSU+JQogIGthYmxlX3BhcGVyKGMoImhvdmVyIiwgInN0cmlwZWQiKSwgZnVsbF93aWR0aCA9IEYpJT4lCiAgY29sdW1uX3NwZWMoYygxLDIpLCBib2xkID0gVCwgY29sb3IgPSAiYmxhY2siKSU+JQogIHNjcm9sbF9ib3goaGVpZ2h0ID0gIjQ1MHB4IikKYGBgCgojIE1vZGVsbGluZwoKUXVlc3Rpb246ICoqSG93IGxvbmcgd291bGQgaXQgdGFrZSB0byBsZWFybiBhIHBpZWNlIGJhc2VkIG9uIHZhcmlvdXMgZmFjdG9ycz8qKgoKIyMgZGV0ZWN0IG91dGxpZXJzCgpHaXZlbiB0aGUgdmVyeSBsaW1pdGVkIGRhdGEgYXQgdGhlIGFkdmFuY2VkIGxldmVsIChHcmFkZSA3IEFCUlNNKSwgdGhvc2UgdHdvIHBpZWNlcyB3aWxsIGJlIHJlbW92ZWQuIE9uZSBpcyBhbiBleHRyZW1lIG91dGxpZXIgYXMgd2VsbCB3aGljaCB3aWxsIHNpZ25pZmljYW50bHkgaW1wYWN0IG91ciBtb2RlbHMuCgpgYGB7cn0KbW9kZWxfZGF0YSA8LSBtb2RlbF9kYXRhJT4lZmlsdGVyKEFCUlNNICE9IDcpJT4lZHJvcGxldmVscygpCmBgYAoKIyMgbWlzc2luZyB2YWx1ZXMKClRoZXJlIGFyZSBubyBtaXNzaW5nIHZhbHVlcyBpbiB0aGUgbW9kZWxsaW5nIGRhdGFzZXQgZm9sbG93aW5nIHRoZSBFVEwgcHJvY2Vzcy4KCiMjIEZlYXR1cmUgZW5naW5lZXJpbmcKCiogKipjYXRlZ29yaWNhbCoqOgogICogKipBQlJTTSBncmFkZSoqOiAxIHRvIDgKICAqICoqR2VucmUqKjogQmFyb3F1ZSwgQ2xhc3NpY2FsLCBSb21hbnRpYywgTW9kZXJuCiAgKiAqKkJyZWFrKio6IGxlYXJuaW5nIGl0IGNvbnRpbnVvdXNseSBvciBzZXR0aW5nIGl0IGFzaWRlIGZvciBhIHdoaWxlICgxIG1vbnRoIG1pbmltdW0pCiAgKiAqKlN0YW5kYXJkKiogb2YgcHJhY3RpY2U6IHB1YmxpYyBwZXJmb3JtYW5jZSBvciBhdmVyYWdlIChyZWxhdGl2ZSB0byBzb21lb25lJ3MgbGV2ZWwgb2YgcGxheWluZykKKiAqKm51bWVyaWNhbCoqOgogICogKipFeHBlcmllbmNlKio6IHRvdGFsIGhvdXJzIHByYWN0aWNlZCBiZWZvcmUgdGhlIGZpcnN0IHByYWN0aWNlIHNlc3Npb24gb24gZWFjaCBwaWVjZQogICogcGllY2UgKipMZW5ndGgqKjogbWludXRlcwoKIyMgUHJlLXByb2Nlc3NpbmcKCkxldCdzIHVzZSBzb21lIGJhc2ljIHN0YW5kYXJkaXNhdGlvbiBvZmZlcmVkIGJ5IHRoZSBjYXJldCBwYWNrYWdlIHN1Y2ggYXMgKipjZW50ZXJpbmcqKiAoc3VidHJhY3QgbWVhbiBmcm9tIHZhbHVlcykgYW5kICoqc2NhbGluZyoqIChkaXZpZGUgdmFsdWVzIGJ5IHN0YW5kYXJkIGRldmlhdGlvbikuCgpgYGB7cn0Kc2V0LnNlZWQoMTIzKQoKIyBzZXQgYSBiYWNrdXAgdmFyaWFibGUKYmFja3VwIDwtIG1vZGVsX2RhdGEKCnkgPC0gbW9kZWxfZGF0YSREdXJhdGlvbgoKIyB0YWtlIG91dCBvdXIgcmVzcG9uc2UgdmFyaWFibGUgdGVtcG9yYXJpbHkgYXMgd2UgZG8gbm90IHdhbnQgdGhpcyB0byBiZSBwcm9jZXNzZWQKbW9kZWxfZGF0YSA8LSBtb2RlbF9kYXRhICU+JQogIHNlbGVjdCgtRHVyYXRpb24pCgojIGNlbnRlciBhbmQgc2NhbGUgb3VyIGRhdGEgKEJveENveCBpZiBuZWVkZWQpCnByZVByb2Nlc3NfcmFuZ2VfbW9kZWwgPC0gcHJlUHJvY2Vzcyhtb2RlbF9kYXRhLCBtZXRob2Q9YygiY2VudGVyIiwgInNjYWxlIikpIAoKbW9kZWxfZGF0YSA8LSBwcmVkaWN0KHByZVByb2Nlc3NfcmFuZ2VfbW9kZWwsIG5ld2RhdGEgPSBtb2RlbF9kYXRhKQogCiMgYXBwZW5kIHRoZSBZIHZhcmlhYmxlIGJhY2sgb24gd2l0aCBvcmlnaW5hbCB2YWx1ZXMKbW9kZWxfZGF0YSREdXJhdGlvbiA8LSB5CmBgYAoKIyMgUmVzYW1wbGluZwoKR2l2ZW4gdGhlIHNtYWxsIHNpemUgb2YgdGhlIGRhdGFzZXQsIGJvb3RzdHJhcHBpbmcgcmVzYW1wbGluZyBtZXRob2Qgd2lsbCBiZSBhcHBsaWVkLgoKYGBge3J9CnRyYWluLmNvbnRyb2wgPC0gdHJhaW5Db250cm9sKG1ldGhvZCA9ICJib290IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbnVtYmVyID0gMjUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlYXJjaCA9ICJyYW5kb20iKQpgYGAKCiMjIE1vZGVsIHNlbGVjdGlvbgoKYGBge3IgZWNobz1UUlVFLCBjYWNoZSA9IFRSVUUsIHJlc3VsdHM9J2hpZGUnfQojIHNldCBudW1iZXIgb2YgY2x1c3RlcnMgCmNsdXN0ZXJzIDwtIDQKCiMgcnVuIHRoZW0gYWxsIGluIHBhcmFsbGVsCmNsIDwtIG1ha2VDbHVzdGVyKGNsdXN0ZXJzLCB0eXBlID0gIlNPQ0siKQogCiMgcmVnaXN0ZXIgY2x1c3RlciB0cmFpbiBpbiBwYXJhbGVsCnJlZ2lzdGVyRG9TTk9XKGNsKQoKIyB0cmFpbiBtb2RlbHMKbW9kZWwgPC0gdHJhaW4oRHVyYXRpb24gfiBBQlJTTSArIEdlbnJlICsgTGVuZ3RoICsgQ3VtdWxhdGl2ZV9EdXJhdGlvbiArIEJyZWFrICsgU3RhbmRhcmQsCiAgICAgICAgICAgICAgICAgIGRhdGEgPSBtb2RlbF9kYXRhLAogICAgICAgICAgICAgICAgICBtZXRob2QgPSAicmFuZ2VyIiwKICAgICAgICAgICAgICAgICAgdHVuZUxlbmd0aCA9IDEwMCwKICAgICAgICAgICAgICAgICAgdHJDb250cm9sID0gdHJhaW4uY29udHJvbCkKCgptb2RlbDIgPC0gdHJhaW4oRHVyYXRpb24gfiBBQlJTTSArIEdlbnJlICsgTGVuZ3RoICsgQ3VtdWxhdGl2ZV9EdXJhdGlvbiArIEJyZWFrICsgU3RhbmRhcmQsCiAgICAgICAgICAgICAgICBkYXRhID0gbW9kZWxfZGF0YSwKICAgICAgICAgICAgICAgIG1ldGhvZCA9ICJsbVN0ZXBBSUMiLAogICAgICAgICAgICAgICAgdHVuZUxlbmd0aCA9IDEwMCwKICAgICAgICAgICAgICAgIHRyQ29udHJvbCA9IHRyYWluLmNvbnRyb2wpCgoKbW9kZWwzIDwtIHRyYWluKER1cmF0aW9uIH4gQUJSU00gKyBHZW5yZSArIExlbmd0aCArIEN1bXVsYXRpdmVfRHVyYXRpb24gKyBCcmVhayArIFN0YW5kYXJkLAogICAgICAgICAgICAgICAgZGF0YSA9IG1vZGVsX2RhdGEsCiAgICAgICAgICAgICAgICBtZXRob2QgPSAibG0iLAogICAgICAgICAgICAgICAgdHVuZUxlbmd0aCA9IDEwMCwKICAgICAgICAgICAgICAgIHRyQ29udHJvbCA9IHRyYWluLmNvbnRyb2wpCgptb2RlbDQgPC0gdHJhaW4oRHVyYXRpb24gfiBBQlJTTSArIEdlbnJlICsgTGVuZ3RoICsgQ3VtdWxhdGl2ZV9EdXJhdGlvbiArIEJyZWFrICsgU3RhbmRhcmQsCiAgICAgICAgICAgICAgICBkYXRhID0gbW9kZWxfZGF0YSwKICAgICAgICAgICAgICAgIG1ldGhvZCA9ICJyaWRnZSIsCiAgICAgICAgICAgICAgICB0dW5lTGVuZ3RoID0gMTAwLAogICAgICAgICAgICAgICAgdHJDb250cm9sID0gdHJhaW4uY29udHJvbCkKCm1vZGVsNSA8LSB0cmFpbihEdXJhdGlvbiB+IEFCUlNNICsgR2VucmUgKyBMZW5ndGggKyBDdW11bGF0aXZlX0R1cmF0aW9uICsgQnJlYWsgKyBTdGFuZGFyZCwKICAgICAgICAgICAgICAgIGRhdGEgPSBtb2RlbF9kYXRhLAogICAgICAgICAgICAgICAgbWV0aG9kID0gInJmIiwKICAgICAgICAgICAgICAgIHR1bmVMZW5ndGggPSAxMDAsCiAgICAgICAgICAgICAgICB0ckNvbnRyb2wgPSB0cmFpbi5jb250cm9sKQoKbW9kZWw2IDwtIHRyYWluKER1cmF0aW9uIH4gQUJSU00gKyBHZW5yZSArIExlbmd0aCArIEN1bXVsYXRpdmVfRHVyYXRpb24gKyBCcmVhayArIFN0YW5kYXJkLAogICAgICAgICAgICAgICAgZGF0YSA9IG1vZGVsX2RhdGEsCiAgICAgICAgICAgICAgICBtZXRob2QgPSAiZ2JtIiwKICAgICAgICAgICAgICAgIHR1bmVMZW5ndGggPSAxMDAsCiAgICAgICAgICAgICAgICB0ckNvbnRyb2wgPSB0cmFpbi5jb250cm9sKQoKbW9kZWw3IDwtIHRyYWluKER1cmF0aW9uIH4gQUJSU00gKyBHZW5yZSArIExlbmd0aCArIEN1bXVsYXRpdmVfRHVyYXRpb24gKyBCcmVhayArIFN0YW5kYXJkLAogICAgICAgICAgICAgICAgZGF0YSA9IG1vZGVsX2RhdGEsCiAgICAgICAgICAgICAgICBtZXRob2QgPSAicGxzIiwKICAgICAgICAgICAgICAgIHR1bmVMZW5ndGggPSAxMDAsCiAgICAgICAgICAgICAgICB0ckNvbnRyb2wgPSB0cmFpbi5jb250cm9sKQogCiMgc2h1dCB0aGUgaW5zdGFuY2VzIG9mIFIgZG93bgpzdG9wQ2x1c3RlcihjbCkKCiMgY29tcGFyZSBtb2RlbHMKbW9kZWxfbGlzdCA8LSBsaXN0KHJhbmdlciA9IG1vZGVsLCBsbVN0ZXBBSUMgPSBtb2RlbDIsIGxtID0gbW9kZWwzLCByaWRnZSA9IG1vZGVsNCwgcmYgPSBtb2RlbDUsIGdibSA9IG1vZGVsNiwgcGxzID0gbW9kZWw3KQoKbW9kZWxfY29tcGFyaXNvbiA8LSByZXNhbXBsZXMobW9kZWxfbGlzdCkKCiMgbGVhcm5pbmcgY3VydmVzIHRvIGluZGljYXRlIG92ZXJmaXR0aW5nIGFuZCB1bmRlcmZpdHRpbmcKIyBoeXBlciBwYXJhbWV0ZXJzIAojIGh0dHBzOi8vdG9wZXBvLmdpdGh1Yi5pby9jYXJldC9tb2RlbC10cmFpbmluZy1hbmQtdHVuaW5nLmh0bWwjbW9kZWwtdHJhaW5pbmctYW5kLXBhcmFtZXRlci10dW5pbmcKIyBodHRwczovL3RvcGVwby5naXRodWIuaW8vY2FyZXQvcmFuZG9tLWh5cGVycGFyYW1ldGVyLXNlYXJjaC5odG1sCmBgYAoKV2UgY2hvc2UgdGhlIFJhbmRvbSBGb3Jlc3QgbW9kZWwgYXMgaXQgd2FzIHRoZSBiZXN0IHBlcmZvcm1pbmcgbW9kZWwuIEl0IGlzIGtub3duIGFzIGEgbW9kZWwgd2hpY2ggaXM6CgoqIG5vdCB2ZXJ5IHNlbnNpdGl2ZSB0byBvdXRsaWVycwoqIGdvb2QgZm9yIG5vbi1saW5lYXJpdHkKKiB2YXJpYWJsZSBpbXBvcnRhbmNlIGNhbiBiZSBiaWFzZWQgaWYgY2F0ZWdvcmljYWwgdmFyaWFibGVzIGhhdmUgZmV3IGxldmVscyAodG93YXJkIGhpZ2ggbGV2ZWxzKSBvciBhcmUgY29ycmVsYXRlZAoKYGBge3J9CnN1bW1hcnkobW9kZWxfY29tcGFyaXNvbikKYGBgCgpCYXNlZCBvbiBvdXIgcmVncmVzc2lvbiBtb2RlbCwgaXQgZG9lcyBub3QgbG9vayBsaWtlIHdlIGhhdmUgc2lnbmlmaWNhbnQgbXVsdGljb2xsaW5lYXJpdHkgYmV0d2VlbiB0aGUgZnVsbCBtb2RlbCB2YXJpYWJsZXMgc28gd2UgY2FuIGNvbnRpbnVlIGFzIGl0IGlzLgoKYGBge3J9CnRpZHkodmlmKG1vZGVsMyRmaW5hbE1vZGVsKSklPiUKICByZW5hbWUoVklGID0geCklPiUKICBtdXRhdGUoVklGID0gcm91bmQoVklGLCAxKSklPiUKICBhcnJhbmdlKGRlc2MoVklGKSklPiUKICBrYmwoY2FwdGlvbiA9ICJWYXJpYW5jZSBJbmZsYXRpb24gRmFjdG9yIChWSUYpIiklPiUKICBrYWJsZV9wYXBlcigiaG92ZXIiLCBmdWxsX3dpZHRoID0gRikKYGBgCgojIyMgQWN0dWFscyB2cyBQcmVkaWN0aW9ucwoKYGBge3J9CnNlbGVjdGVkX21vZGVsIDwtIG1vZGVsNQoKI1NhdmluZyB0aGUgbW9kZWwKc2F2ZVJEUyhzZWxlY3RlZF9tb2RlbCwgZmlsZSA9ICJtb2RlbC5yZGEiKQoKI2dldCBwcmVkaWN0aW9ucwpwcmVkaWN0aW9ucyA8LSBwcmVkaWN0KHNlbGVjdGVkX21vZGVsLCBtb2RlbF9kYXRhKQoKI2NyZWF0ZSBkYXRhc2V0Cm1vZGVsX2RhdGEyIDwtIG1vZGVsX2RhdGEKbW9kZWxfZGF0YTIkUHJlZGljdGVkIDwtIHByZWRpY3Rpb25zCm1vZGVsX2RhdGEyJEFjdHVhbCA8LSBtb2RlbF9kYXRhJER1cmF0aW9uCm1vZGVsX2RhdGEyJFJlc2lkdWFscyA8LSBtb2RlbF9kYXRhMiRBY3R1YWwgLSBtb2RlbF9kYXRhMiRQcmVkaWN0ZWQKCiMgbW9kZWxfZGF0YTIgPC0gbW9kZWxfZGF0YSU+JQojICAgbXV0YXRlKEFjdHVhbCA9IGFzLm51bWVyaWMoRHVyYXRpb24pLAojICAgICAgICAgIFByZWRpY3RlZCA9IGFzLm51bWVyaWMocHJlZGljdGlvbnMpLAojICAgICAgICAgIFJlc2lkdWFscyA9IEFjdHVhbCAtIFByZWRpY3RlZCklPiUKIyAgIHNlbGVjdChQcmVkaWN0ZWQsIEFjdHVhbCwgUmVzaWR1YWxzLCBQcm9qZWN0LCBMZXZlbCwgR2VucmUpCgojdmlzdWFsaXNlIHByZWRpY3RlZCB2cyBhY3R1YWwKZ2dwbG90bHkoCmdncGxvdChtb2RlbF9kYXRhMiwgYWVzKFByZWRpY3RlZCwgQWN0dWFsLCBsYWJlbCA9IFJlc2lkdWFscywgY29sID0gTGV2ZWwpKSsKICBnZW9tX3BvaW50KGFlcyh0ZXh0ID0gUHJvamVjdCksIHNpemUgPSAzLCBhbHBoYSA9IDAuNzUpKwogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsb2VzcyIsIGNvbCA9ICJyZWQiLCBsd2QgPSAxLCBzZSA9IEZBTFNFKSsKICBnZW9tX2FibGluZShsdHkgPSAiZGFzaGVkIiwgbHdkID0gMC41LCBjb2wgPSAiZ3JheSIpKwogIGNvb3JkX2NhcnRlc2lhbih4bGltID0gYygwLDUwKSwgeWxpbSA9IGMoMCw1MCkpKwogIGxhYnMoY29sID0gTlVMTCkrCiAgc2NhbGVfY29sb3JfdHJvbigpKwogIHRoZW1lX2lwc3VtX2VzKCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiKQopICU+JQogIGxheW91dChsZWdlbmQgPSBsaXN0KG9yaWVudGF0aW9uID0gImgiLCB4ID0gMC40LCB5ID0gMS4yKSkKYGBgCgojIyMgUmVzaWR1YWwgZGlzdHJpYnV0aW9uCgpXZSBjYW4gc2VlIHRoYXQgdGhlIHJlc2lkdWFscyBhcmUgbW9zdGx5IHNpdHVhdGVkIGFyb3VuZCAwLgoKYGBge3J9CmdncGxvdChtb2RlbF9kYXRhMiwgYWVzKFJlc2lkdWFscywgZmlsbCA9IC4uY291bnQuLikpKwogIGdlb21faGlzdG9ncmFtKGJpbndpZHRoID0gMSwgY29sID0gImJsYWNrIikrCiAgZ2VvbV92bGluZShhZXMoeGludGVyY2VwdD1tZWFuKFJlc2lkdWFscykpLCBsd2QgPSAxLCBsdHkgPSAyKSArCiAgbGFicyh4PSJSZXNpZHVhbHMiLAogICAgICAgeT0gIlRvdGFsIG9jY3VyZW5jZXMiKSsKICBzY2FsZV9maWxsX2dyYWRpZW50KGxvdz0ieWVsbG93IiwgaGlnaD0icmVkIikrCiAgdGhlbWVfaXBzdW1fZXMoKSsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpCmBgYAoKIyMjIEFjdHVhbHMgdmVyc3VzIFJlc2lkdWFscwoKTG9va2luZyBhdCB0aGUgdmFyaWFiaWxpdHkgb2YgZXJyb3JzLCB0aGVyZSBpcyBzdGlsbCBhIHRlbmRlbmN5IHRvIG92ZXItcHJlZGljdCBmb3IgcGllY2VzIHRoYXQgdG9vayB2ZXJ5IGxpdHRsZSBhbmQgdW5kZXItcHJlZGljdCBmb3IgdGhlIG1vcmUgZGlmZmljdWx0IG9uZXMuIFRoZXJlIGNvdWxkIGJlIHR3byBtYWluIHJlYXNvbnMgZm9yIHRoaXM6CgoqIHByYWN0aWNpbmcgYW4gb2xkIHBpZWNlIGluIG9yZGVyIHRvIGZ1cnRoZXIgaW1wcm92ZSAod2hpY2ggbmF0dXJhbGx5IGFkZHMgbW9yZSBwcmFjdGljZSB0aW1lIGFzIEkgcmUtbGVhcm4gaXQpCiogbGVhcm5pbmcgZWFzaWVyIHBpZWNlcyBsYXRlciBvbiBpbiBteSBqb3VybmV5IHdoaWNoIG1lYW5zIEkgd2lsbCBsZWFybiB0aGVtIGZhc3RlciB0aGFuIGV4cGVjdGVkIChiYXNlZCBvbiBteSBlYXJsaWVyIGRhdGEgd2hlcmUgYSBwaWVjZSBvZiBhIHNpbWlsYXIgZGlmZmljdWx0eSB0b29rIGxvbmdlcikKCmBgYHtyfQpnZ3Bsb3RseSgKZ2dwbG90KG1vZGVsX2RhdGEyLCBhZXMoQWN0dWFsLCBSZXNpZHVhbHMsIGNvbCA9IExldmVsLCBsYWJlbCA9IFByZWRpY3RlZCkpKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIHNpemUgPSAzLCBjb2xvciA9ICJncmV5NTIiKSsKICBnZW9tX3BvaW50KGFlcyh0ZXh0ID0gUHJvamVjdCksIGFscGhhID0gMC43NSwgc2l6ZSA9IDMpKwogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsb2VzcyIsIGNvbCA9ICJyZWQiLCBzZSA9IEZBTFNFKSsKICBsYWJzKGNvbCA9IE5VTEwpKwogIHNjYWxlX2NvbG9yX3Ryb24oKSsKICB0aGVtZV9pcHN1bV9lcygpCikgJT4lCiAgbGF5b3V0KGxlZ2VuZCA9IGxpc3Qob3JpZW50YXRpb24gPSAiaCIseCA9IDAuNCwgeSA9IDEuMikpCmBgYAoKIyMgTGluZWFyIFJlZ3Jlc3Npb24gKExSKSBvciBSYW5kb20gRm9yZXN0IChSRik/CgpXZSBjYW4gc2VlIHRoYXQgdGhlIFJhbmRvbSBGb3Jlc3QgcGVyZm9ybWVkIHNpZ25pZmljYW50bHkgYmV0dGVyIHRoYW4gdGhlIExpbmVhciBSZWdyZXNzaW9uIG1vZGVsLiBUaGlzIGlzbid0IHN1cnByaXNpbmcgc2luY2UgdGhlcmUgbWlnaHQgYmUgbm9uLWxpbmVhciB0cmVuZHMgd2l0aGluIHRoZSBkYXRhLCBhbmQgUkZzIGFyZSBrbm93biB0byBiZSBtb3JlIGFjY3VyYXRlLgoKYGBge3J9CnRpZHkoY29tcGFyZV9tb2RlbHMobW9kZWwzLCBtb2RlbDUpKSU+JQogIGtibChjYXB0aW9uID0gIk1vZGVsIDEgdnMgbW9kZWwgMiIpJT4lCiAga2FibGVfcGFwZXIoImhvdmVyIiwgZnVsbF93aWR0aCA9IEYpCmBgYAoKIyMgSG93IG1hbnkgcHJlZGljdG9ycyBkaWQgdGhlIG1vc3Qgb3B0aW1hbCBtb2RlbCBoYXZlPwoKYGBge3IgcHJlZGljdG9yc30KcGxvdChtb2RlbDUsIG1haW4gPSAiVGhlIG1vc3Qgb3B0aW1hbCBtb2RlbCB3YXMgdGhhdCB3aXRoIDYgcHJlZGljdG9ycyIsIGNvbCA9ICJvcmFuZ2UiLCBsd2QgPSAxLjUpCmBgYAoKIyMgV2hhdCB3ZXJlIHRoZSBtb3N0IGltcG9ydGFudCB2YXJpYWJsZXM/CgpXZSBjYW4gbm93IHNlZSB0aGF0IHRoZSBtb3N0IGltcG9ydGFudCB2YXJpYWJsZXMgc2VlbWVkIHRvIGJlIHRoZSBsZW5ndGggb2YgdGhlIHBpZWNlLCBteSBleHBlcmllbmNlIHByaW9yIHRvIHN0YXJ0aW5nIGEgcGllY2UgYW5kIHRpbWUgZGlmZmljdWx0eSBvZiB0aGUgcGllY2UuIFRoZXNlIHdlcmUgYWxzbyBjb25maXJtZWQgYnkgdGhlIGxpbmVhciByZWdyZXNzaW9uIG1vZGVsLgoKYGBge3IgZmFjdG9yc30KaW1wIDwtIGFzLm1hdHJpeCh2YXJJbXAobW9kZWw1KSRpbXBvcnRhbmNlKSU+JQogIGFzLmRhdGEuZnJhbWUoKSU+JQogIHJlbmFtZShJbXBvcnRhbmNlID0gT3ZlcmFsbCklPiUKICBtdXRhdGUoRmVhdHVyZSA9IGFzLmZhY3Rvcihyb3duYW1lcyguKSksCiAgICAgICAgIEZlYXR1cmUgPSByZW9yZGVyKEZlYXR1cmUsIEltcG9ydGFuY2UpKQoKZ2dwbG90KGltcCwgYWVzKEZlYXR1cmUsIEltcG9ydGFuY2UpKSsKICBnZW9tX3NlZ21lbnQoYWVzKEZlYXR1cmUsIHkgPSAwLCB4ZW5kID0gRmVhdHVyZSwgeWVuZCA9IEltcG9ydGFuY2UpLCBjb2wgPSAiYmxhY2siLCBzaXplID0gMS41KSArCiAgZ2VvbV9wb2ludChzaXplID0gMTAsIGNvbCA9ICJvcmFuZ2UiKSsKICBnZW9tX3RleHQoYWVzKGxhYmVsID0gcGFzdGUocm91bmQoSW1wb3J0YW5jZSksICIlIiwgc2VwID0gIiIpKSwgY29sb3IgPSAiYmxhY2siLCBzaXplID0gMywgY2hlY2tfb3ZlcmxhcCA9IFRSVUUpKwogIHNjYWxlX2NvbG9yX3Ryb24oKSsKICBzY2FsZV9maWxsX3Ryb24oKSsKICB0aGVtZV9pcHN1bV9lcygpKwogIGNvb3JkX2ZsaXAoKSsKICBsYWJzKHRpdGxlID0gIlZhcmlhYmxlIGltcG9ydGFuY2UgcmFua2luZyIpKwogIHRoZW1lKGF4aXMudGV4dC54ID0gIGVsZW1lbnRfYmxhbmsoKSwgCiAgICAgICAgYXhpcy50aWNrcyA9IGVsZW1lbnRfYmxhbmsoKSkKCiNwbG90KHZhckltcChtb2RlbDUpKQpgYGAKCiMgTGltaXRhdGlvbnMKCiogdmVyeSAqKmxpbWl0ZWQgZGF0YSoqIHdoaWNoIGRpZCBub3QgYWxsb3cgZm9yIGEgdHJhaW4vdGVzdCBzcGxpdDsgaG93ZXZlciwgYSBib290c3RyYXAgcmVzYW1wbGluZyBtZXRob2QgaXMga25vd24gdG8gYmUgYSBnb29kIHN1YnN0aXR1dGUKKiBiaWFzZWQgdG8gKipvbmUgcGVyc29uJ3MqKiBsZWFybmluZyBhYmlsaXR5IChvdGhlcnMgbWlnaHQgbGVhcm4gZmFzdGVyIG9yIHNsb3dlcikKKiBvbiB0b3Agb2YgdG90YWwgaG91cnMgb2YgcHJhY3RpY2UsICoqcXVhbGl0eSBvZiBwcmFjdGljZSoqIGlzIGEgc2lnbmlmaWNhbnQgZmFjdG9yIHdoaWNoIGlzIG5vdCBjYXB0dXJlZCBpbiB0aGlzIGRhdGFzZXQKKiB2ZXJ5ICoqZGlmZmljdWx0IHRvIGFzc2VzcyB3aGVuIGEgcGllY2UgaXMgImZpbmlzaGVkIioqIGFzIHlvdSBjYW4gYWx3YXlzIGZ1cnRoZXIgaW1wcm92ZSBvbiB5b3VyIGludGVycHJldGF0aW9uCiogbm90IGFsbCBwaWVjZXMgaGFkIG9mZmljaWFsICoqQUJSU00gcmF0aW5ncyoqIGFuZCBhIGZldyBoYWQgdG8gYmUgZXN0aW1hdGVkOyBldmVuIGZvciB0aG9zZSB0aGF0IGRvIGhhdmUgYW4gb2ZmaWNpYWwgcmF0aW5nLCB0aGUgZGlmZmljdWx0eSBvZiBhIHBpZWNlIGlzIGhpZ2hseSBzdWJqZWN0aXZlIHRvIGVhY2ggcGlhbmlzdCBhbmQgaGFyZCB0byBxdWFudGlmeSB3aXRoIG9uZSBudW1iZXIKKiAqKm1lbW9yaXNhdGlvbioqIG1pZ2h0IGJlIGEgY29uZm91bmRpbmcgdmFyaWFibGUgdGhhdCB3YXMgbm90IGFjY291bnRlZCBmb3I7IHNvbWV0aW1lcyB0aGVyZSdzIGFuIGVmZm9ydCB0byBwcmFjdGljZSBhIGJpdCBmb3IgbG9uZ2VyIGp1c3QgdG8gbWVtb3Jpc2Ugd2l0aG91dCBhbiBpbXByb3ZlbWVudCBpbiBwZXJmb3JtYW5jZQoKIyBIYXJkZXN0IHRoaW5ncyBhYm91dCB0aGlzIGFuYWx5c2lzOgoKKiB0aGUgRXh0cmFjdC1UcmFuc2Zvcm0tTG9hZCBwcm9jZXNzIC0gY2xlYW4gdGhlICJkaXJ0eSBkYXRhIiBhbmQgZmluZCBjcmVhdGl2ZSB3YXlzIHRvIGlucHV0IHRoZSBkYXRhIG9uIHRoZSBmcm9udCBlbmQgb2YgdGhlIGFwcCB0byBtYWtlIGl0IHJlcG9ydGluZyBmcmllbmRseSBvbiB0aGUgYmFjay1lbmQgKHdpdGggYWxsIHRoZSB2YXJpYWJsZXMgc3VjaCBhcyBHZW5yZSwgVHlwZSBvZiBwcmFjdGljZSwgQ29tcG9zZXIgYW5kIFBpZWNlIG5hbWUsIHRhZyBwaWVjZXMgYXMgIndvcmsgaW4gcHJvZ3Jlc3MiIGV0YykKKiBhdXRvbWF0ZSB3YXlzIHRvIGRpZmZlcmVudGlhdGUgYmV0d2VlbiBwaWVjZXMgdGhhdCBJIGNhbWUgYmFjayB0byB2cyBwaWVjZXMgSSBvbmx5IHN0dWRpZWQgb25jZQoqIHdvcmsgd2l0aCB2ZXJ5IGxpbWl0ZWQgZGF0YQoKIyBJbnRlcmFjdGl2ZSBhcHBsaWNhdGlvbjoKCiogeW91IGNhbiBmaW5kIGFuIGludGVyYWN0aXZlIGRpc3BsYXkgb2YgdGhpcyBwcmVzZW50YXRpb24sIGFzIHdlbGwgYXMgdGhlIG1vZGVsIGluIHByb2R1Y3Rpb24gYXQgdGhlIFtmb2xsb3dpbmcgbGlua10oaHR0cHM6Ly9wZXRlcmhvbnRhcnUuc2hpbnlhcHBzLmlvL3BpYW5vLXByYWN0aWNlLXByZWRpY3Rpb24vKQoqIGh0dHBzOi8vcGV0ZXJob250YXJ1LnNoaW55YXBwcy5pby9waWFuby1wcmFjdGljZS1wcmVkaWN0aW9uLwoKIyBXaGF0J3MgbmV4dD8KCioga2VlcCBwcmFjdGljaW5nLCBnYXRoZXIgbW9yZSBkYXRhIGFuZCByZWZyZXNoIHRoaXMgYW5hbHlzaXMgKyB1cGRhdGUgdGhlIG1vZGVsCiogYWRkIGEgcmVjb21tZW5kZXIgdGFiIHRvIHRoZSBzaGlueSBkYXNoYm9hcmQgd2hlcmUgcGVvcGxlIGNvdWxkIGJlIHJlY29tbWVuZGVkIGEgcGllY2UgYmFzZWQgb24gc3BlY2lmaWMgZmVhdHVyZXMKKiBjb25uZWN0IHRvIHRoZSBUb2dnbCBBUEkgZm9yIGxpdmUgdXBkYXRlcw==